http://poj.org/problem?id=1639
题目大意:给定一个图,求最小生成树,其中某个节点的度数小于K。
这就是一个最小k限度生成树,我写了好久好久,也有我不熟悉STL的原因,CE了好久……
求最小K度生成树的方法:首先去掉特殊点(v0),然后图会成为x个联通块,求x次最小生成树,然后将这x个生成树连接到v0上。
每次寻找一个点p,满足点p不与v0相联系(边不在生成树上,不是不相连),且与点p相关的在生成树上的边大于点p到v0的距离,舍弃原来的边,并将点p与v0相连。
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <algorithm> #include <stack> #include <queue> #include <deque> #include <map> #include <utility> #include <iterator> #include <cassert> #include <cctype> #include <list> #include <bitset> #include <cmath> #include <functional> #include <set> #include <sstream> #include <ctime> #define mn 301 #define mm 1000 #define inf ~0u>>1 using namespace std; struct EDGE{ int pnt,dist; EDGE *pre; EDGE (){} EDGE(int _pnt,int _dist,EDGE *_pre):pnt(_pnt),dist(_dist),pre(_pre){} }Edge[mm*2],*SP=Edge,*edge[mm]; map<string,int> NameList; char place1[100],place2[100]; int x,y,z,n,names=1,MST,belong[mn],size[mn],blocks,dist[mn],pre[mn],big[mn],K,Link[mn],Point[mn],Degree,places; bool use[mn][mn],vis[mn]; inline void addedge(int a,int b,int c){ edge[a]=new(++SP)EDGE(b,c,edge[a]); edge[b]=new(++SP)EDGE(a,c,edge[b]); } int NameOrder(char s[100]){ if(NameList.find(s)==NameList.end()) NameList[s]=++names; else return NameList[s]; return names; } void Count_Connection_Blocks(int x){ vis[x]=true,belong[x]=blocks,size[blocks]++; for(EDGE *j=edge[x];j;j=j->pre) if(!vis[j->pnt]) Count_Connection_Blocks(j->pnt); } void Prim(int cur){ for(int i=1;i<=names;i++) dist[i]=inf; for(int i=1;i<=names;i++) if(belong[i]==cur){ dist[i]=0; break; } for(int k=1;k<=size[cur];k++){ int mind=inf,minp; for(int i=1;i<=names;i++) if(!vis[i] && mind>dist[i]) mind=dist[i],minp=i; MST+=dist[minp],vis[minp]=true; for(EDGE *j=edge[minp];j;j=j->pre) if(!vis[j->pnt] && dist[j->pnt]>j->dist) dist[j->pnt]=j->dist,pre[j->pnt]=minp; } } void Mark(int u,int v,bool symble){ use[u][v]=symble,use[v][u]=symble; } void DP(int x,int fa){ pre[x]=fa; for(EDGE *j=edge[fa];j;j=j->pre) if(j->pnt==x){ if(fa!=1) big[x]=max(big[fa],j->dist); else big[x]=0; break; } for(EDGE *j=edge[x];j;j=j->pre) if(use[x][j->pnt] && j->pnt!=fa) DP(j->pnt,x); } int main(){ scanf("%d",&n); NameList["Park"]=1; for(int i=1;i<=n;i++){ scanf("%s%s%d",place1,place2,&z); addedge(NameOrder(place1),NameOrder(place2),z); } scanf("%d",&K); vis[1]=true; for(int i=2;i<=names;i++) if(!vis[i]){ blocks++; Count_Connection_Blocks(i); } memset(vis,false,sizeof(vis));vis[1]=true; for(int i=1;i<=blocks;i++) Prim(i); for(int i=2;i<=n;i++) Mark(pre[i],i,true); memset(Link,0x7f,sizeof(Link)); for(EDGE *j=edge[1];j;j=j->pre) if(Link[belong[j->pnt]]>j->dist) Link[belong[j->pnt]]=j->dist,Point[belong[j->pnt]]=j->pnt; for(int i=1;i<=blocks;i++){ MST+=Link[i]; Mark(1,Point[i],true); } Degree=blocks; addedge(0,1,0); DP(1,0); while(Degree<K){ int maxd=0,maxp=0; for(EDGE *j=edge[1];j;j=j->pre) if(!use[1][j->pnt] && big[j->pnt]-j->dist>maxd) maxd=big[j->pnt]-j->dist,maxp=j->pnt; if(!maxp) break; MST-=maxd,Degree++; int i=maxp;EDGE *j; while(true){ for(j=edge[i];j;j=j->pre) if(j->pnt==pre[i]) break; if(j->dist==big[maxp]) break; else i=pre[i]; } Mark(i,pre[i],false); pre[maxp]=1;DP(maxp,1); } printf("Total miles driven: %d\n",MST); return 0; }