版权声明:转载请注明原出处啦QAQ(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/83111663
题目:POJ1639.
题目大意:给定一张无向图,求这张无向图的最小生成树,其中这棵最小生成树满足节点1的度小于等于s.
我们对于一张图,先将点1去掉,剩下的联通块内的的最小生成树都求出,然后我们在枚举与1关联的边,将所有联通块与1只连一条最小的边,这样我们就求出了一棵最小T度生成树,其中T等于去掉点1后联通块数量.
我们求出最小T度生成树之后,我们再求最小S度生成树.注意,我们下面所说的最小k度指的是点1的度必须为k.
我们考虑最小k度生成树如何转移到最小k+1度生成树.我们考虑枚举一条与1相连但没有被选入最小生成树的边(1,x),然后我们会发现出现了一个环,其中这个环由一条非树边(1,x)和一条树链(x,1)组成.
我们考虑暴力枚举树链上的每一条,找到边权最大的边,看是否最优即可.
但是这样做的时间复杂度最坏情况下为,我们考虑更加优秀的做法.
我们发现这个算法的瓶颈在于枚举到一个点时需要在枚举至多级别条边,那么我们是否可以考虑优化这个过程.
我们考虑每一次转移都先进行一个树形DP,这个DP的状态f[x]表示树上的链(1,x)上的最大边权,并且记录这条边的编号,方便删除.
那么时间复杂度为.
由于时限宽松,这里写了邻接矩阵写法的dfs,若要达到上述那个更优的时间复杂度,需要写一个双向链表形式的邻接表.
代码如下:
#include<iostream>
#include<cstdio>
#include<map>
#include<algorithm>
using namespace std;
#define Abigail inline void
#define mt map<string,int>::iterator
typedef long long LL;
const int N=300,INF=(1<<29)-1;
map<string,int>q;
struct graph_side{
int x,y,v;
bool operator < (const graph_side p)const{return v<p.v;}
}e[N+9];
int m,n,s,ans;
int fa[N+9];
int tr[N+9][N+9],g[N+9][N+9];
struct node{
int x,y,v;
}dp[N+9];
int get(int u){return u^fa[u]?fa[u]=get(fa[u]):u;}
int kruskal(){
int cnt=0;
for (int i=1;i<=n;i++) fa[i]=i;
sort(e+1,e+1+m);
for (int i=1;i<=m;i++){
if (e[i].x==1||e[i].y==1) continue;
int grx=get(e[i].x),gry=get(e[i].y);
if (grx==gry) continue;
fa[grx]=gry;
tr[e[i].x][e[i].y]=tr[e[i].y][e[i].x]=1;
ans+=e[i].v;
}
for (int i=1;i<=m;i++){
if (e[i].x^1&&e[i].y^1) continue;
int grx=get(e[i].x),gry=get(e[i].y);
if (grx==gry) continue;
cnt++;
fa[grx]=gry;
tr[e[i].x][e[i].y]=tr[e[i].y][e[i].x]=1;
ans+=e[i].v;
}
return cnt;
}
void dfs(int k,int fa){
for (int i=2;i<=n;i++)
if (i^fa&&tr[k][i]){
dp[i].v=g[k][i];dp[i].x=k;dp[i].y=i;
if (dp[i].v<dp[k].v) dp[i]=dp[k];
dfs(i,k);
}
}
Abigail into(){
string s1,s2;
mt it;
int v;
for (int i=1;i<=N;i++)
for (int j=1;j<=N;j++)
g[i][j]=INF;
scanf("%d",&m);
q.insert(make_pair("Park",n=1));
for (int i=1;i<=m;i++){
cin>>s1>>s2;
it=q.find(s1);
if (it==q.end()){
e[i].x=++n;
q.insert(make_pair(s1,n));
}else e[i].x=q[s1];
it=q.find(s2);
if (it==q.end()){
e[i].y=++n;
q.insert(make_pair(s2,n));
}else e[i].y=q[s2];
scanf("%d",&e[i].v);
g[e[i].x][e[i].y]=g[e[i].y][e[i].x]=min(e[i].v,g[e[i].x][e[i].y]);
}
scanf("%d",&s);
}
Abigail work(){
int cnt=kruskal();
for (int i=cnt+1;i<=s;i++){
dfs(1,0);
int minn=INF,v=0;
for (int j=2;j<=n;j++)
if (!tr[1][j]&&minn>g[1][j]-dp[j].v) minn=g[1][j]-dp[j].v,v=j;
if (minn>=0||!v) break;
ans+=minn;
tr[1][v]=tr[v][1]=1;
tr[dp[v].x][dp[v].y]=tr[dp[v].y][dp[v].x]=0;
}
}
Abigail outo(){
printf("Total miles driven: %d\n",ans);
}
int main(){
int T=1,_=0;
while (T--){
into();
work();
outo();
}
return 0>_<0;
}