最小生成树专题

来源:互联网 发布:angularjs.min.js下载 编辑:程序博客网 时间:2024/06/07 01:34

专题地址:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=66965#overview

A 裸的最小生成树,Kruskal算法。

[cpp] view plaincopy
  1. #define rd(x) scanf("%d",&x)  
  2. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  3. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  4. using namespace std;  
  5. typedef long long ll;  
  6. const int maxn=3000;  
  7. const int maxm=100000;  
  8. int parent[maxn];  
  9. int tot;  
  10.   
  11. struct Edge  
  12. {  
  13.     int u,v,w;  
  14. }edge[maxm];  
  15.   
  16. void addedge(int u,int v,int w)  
  17. {  
  18.     edge[tot].u=u;  
  19.     edge[tot].v=v;  
  20.     edge[tot++].w=w;  
  21. }  
  22.   
  23. int find(int x)  
  24. {/* 
  25.     if(parent[x]==x) 
  26.         return x; 
  27.     parent[x]=find(parent[x]); 
  28.     return parent[x];*/  
  29.     return parent[x]==x?x:find(parent[x]);  
  30. }  
  31. bool cmp(Edge a,Edge b)  
  32. {  
  33.     return a.w<b.w;  
  34. }  
  35.   
  36. void init(int n)  
  37. {  
  38.     for(int i=0;i<=n;i++)  
  39.         parent[i]=i;  
  40.     tot=0;  
  41. }  
  42.   
  43. int kruscal(int n)  
  44. {  
  45.     sort(edge,edge+tot,cmp);  
  46.     int cnt=0;  
  47.     int ans=0;  
  48.     for(int i=0;i<tot;i++)  
  49.     {  
  50.         int u=edge[i].u;  
  51.         int v=edge[i].v;  
  52.         int w=edge[i].w;  
  53.         int t1=find(u);  
  54.         int t2=find(v);  
  55.         if(t1!=t2)  
  56.         {  
  57.             parent[t1]=t2;  
  58.             ans+=w;  
  59.             cnt++;  
  60.         }  
  61.         if(cnt==n-1)  
  62.             break;  
  63.     }  
  64.     if(cnt<n-1)  
  65.         return -1;  
  66.     else  
  67.         return ans;  
  68. }  
  69.   
  70. int n;  
  71.   
  72. int main()  
  73. {  
  74.     while(rd(n)!=EOF&&n)  
  75.     {  
  76.         char ch;int m;  
  77.         init(n);  
  78.         for(int i=1;i<=n-1;i++)  
  79.         {  
  80.             cin>>ch;  
  81.             int u=ch-'A'+1;  
  82.             rd(m);  
  83.             char to;int w;  
  84.             while(m--)  
  85.             {  
  86.                 cin>>to;  
  87.                 int v=to-'A'+1;  
  88.                 rd(w);  
  89.                 addedge(u,v,w);  
  90.             }  
  91.         }  
  92.         printf("%d\n",kruscal(n));  
  93.     }  
  94.     return 0;  
  95. }  

B 裸的最小生成树,用Prim算法。注意两点之间可能有多条边。

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #define rd(x) scanf("%d",&x)  
  2. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  3. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  4. using namespace std;  
  5. typedef long long ll;  
  6. const int maxn=60;  
  7. const int inf=0x3f3f3f3f;  
  8. int cost[maxn][maxn];  
  9. bool vis[maxn];  
  10. int lowc[maxn];  
  11. int n,m;  
  12.   
  13. int Prim(int cost[][maxn],int n)  
  14. {  
  15.     int ans=0;  
  16.     memset(vis,0,sizeof(vis));  
  17.     vis[0]=true;  
  18.     for(int i=1;i<n;i++)  
  19.         lowc[i]=cost[0][i];  
  20.     for(int i=1;i<n;i++)  
  21.     {  
  22.         int minc=inf;  
  23.         int p=-1;  
  24.         for(int j=0;j<n;j++)  
  25.             if(!vis[j]&&minc>lowc[j])  
  26.         {  
  27.             minc=lowc[j];  
  28.             p=j;  
  29.         }  
  30.         if(minc==inf) return -1;//不连通  
  31.         ans+=minc;  
  32.         vis[p]=true;  
  33.         for(int j=0;j<n;j++)  
  34.             if(!vis[j]&&lowc[j]>cost[p][j])  
  35.             lowc[j]=cost[p][j];  
  36.     }  
  37.     return ans;  
  38. }  
  39.   
  40.   
  41. int main()  
  42. {  
  43.     while(rd(n)!=EOF&&n)  
  44.     {  
  45.         rd(m);  
  46.         int u,v,w;  
  47.         memset(cost,inf,sizeof(cost));  
  48.         while(m--)  
  49.         {  
  50.             rd3(u,v,w);  
  51.             u--;v--;  
  52.             if(w<cost[u][v])  
  53.             {  
  54.                 cost[u][v]=w;  
  55.                 cost[v][u]=w;  
  56.             }  
  57.         }  
  58.         printf("%d\n",Prim(cost,n));  
  59.     }  
  60.     return 0;  
  61. }  

C 空间中有n个小球,给出每个小球的三维坐标和半径,小球可以相互接触也可以重叠,n个小球连接起来,求最小的通道长度。计算任意两个小球之间的距离(注意接触或者重叠距离为0),然后用最小生成树就可以了。

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #define rd(x) scanf("%d",&x)  
  2. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  3. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  4. using namespace std;  
  5. typedef long long ll;  
  6. const int maxn=110;  
  7. double cost[maxn][maxn];  
  8. bool vis[maxn];  
  9. const double inf=1000000;  
  10. const double eps=1e-8;  
  11. double lowc[maxn];  
  12.   
  13. struct Point  
  14. {  
  15.     double x,y,z,r;  
  16.     void input()  
  17.     {  
  18.         scanf("%lf%lf%lf%lf",&x,&y,&z,&r);  
  19.     }  
  20.     double distance(Point p)  
  21.     {  
  22.         double dis=sqrt((x-p.x)*(x-p.x)+(y-p.y)*(y-p.y)+(z-p.z)*(z-p.z));  
  23.         if(dis-r-p.r>eps)  
  24.             return dis-r-p.r;  
  25.         else  
  26.             return 0;  
  27.     }  
  28. }point[maxn];  
  29. int n;  
  30.   
  31. double Prim(double cost[][maxn],int n)  
  32. {  
  33.     memset(vis,0,sizeof(vis));  
  34.     double ans=0;  
  35.     vis[0]=1;  
  36.     for(int i=1;i<n;i++)  
  37.         lowc[i]=cost[0][i];  
  38.     for(int i=1;i<n;i++)  
  39.     {  
  40.         double minc=inf;  
  41.         int p=-1;  
  42.         for(int j=0;j<n;j++)  
  43.         {  
  44.             if(minc>lowc[j]&&!vis[j])  
  45.             {  
  46.                 p=j;  
  47.                 minc=lowc[j];  
  48.             }  
  49.         }  
  50.         ans+=minc;  
  51.         vis[p]=1;  
  52.         for(int j=0;j<n;j++)  
  53.         {  
  54.             if(!vis[j]&&lowc[j]>cost[p][j])  
  55.                 lowc[j]=cost[p][j];  
  56.         }  
  57.     }  
  58.     return ans;  
  59. }  
  60. int main()  
  61. {  
  62.     while(rd(n)!=EOF&&n)  
  63.     {  
  64.         for(int i=0;i<n;i++)  
  65.         {  
  66.             point[i].input();  
  67.         }  
  68.         for(int i=0;i<n;i++)  
  69.             for(int j=0;j<n;j++)  
  70.                 cost[i][j]=inf;  
  71.         for(int i=0;i<n;i++)  
  72.             for(int j=0;j<n;j++)  
  73.         {  
  74.             double dis=point[i].distance(point[j]);  
  75.             if(dis<cost[i][j])  
  76.                 cost[i][j]=cost[j][i]=dis;  
  77.         }  
  78.         printf("%.3f\n",Prim(cost,n));  
  79.     }  
  80.     return 0;  
  81. }  

D 有N个村庄,给定任意两个村庄之间的距离,并且给出一些已经存在的路(边),问最少共再需要多长的路使得N个村庄联通。最小生成树,本题就是有个条件已经存在一些边了,用Prim算法求的是总长度,且每次都是找的最小的边,那么只要把已经存在的边权值设为0就好了,因为每次都是找最小的边,那么这些边肯定会被选择的,而且用prim算法求完后也正好是题目所求的长度。

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #define rd(x) scanf("%d",&x)  
  2. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  3. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  4. using namespace std;  
  5. typedef long long ll;  
  6. const int maxn=104;  
  7. const int inf=0x3f3f3f3f;  
  8. int cost[maxn][maxn];  
  9. int lowc[maxn];  
  10. bool vis[maxn];  
  11. int n,m;  
  12.   
  13. int Prim(int cost[][maxn],int n)  
  14. {  
  15.     int ans=0;  
  16.     memset(vis,0,sizeof(vis));  
  17.     vis[0]=true;  
  18.     for(int i=1;i<n;i++)  
  19.         lowc[i]=cost[0][i];  
  20.     for(int i=1;i<n;i++)//寻找这么多次  
  21.     {  
  22.         int p=-1,minc=inf;  
  23.         for(int j=0;j<n;j++)  
  24.         {  
  25.             if(minc>lowc[j]&&!vis[j])  
  26.             {  
  27.                 minc=lowc[j];  
  28.                 p=j;  
  29.             }  
  30.         }  
  31.         vis[p]=1;  
  32.         ans+=minc;  
  33.         for(int j=0;j<n;j++)  
  34.         {  
  35.             if(!vis[j]&&lowc[j]>cost[p][j])  
  36.                 lowc[j]=cost[p][j];  
  37.         }  
  38.     }  
  39.     return ans;  
  40. }  
  41.   
  42.   
  43. int main()  
  44. {  
  45.     rd(n);  
  46.     memset(cost,inf,sizeof(cost));  
  47.     for(int i=0;i<n;i++)  
  48.         for(int j=0;j<n;j++)  
  49.     {  
  50.         rd(cost[i][j]);  
  51.     }  
  52.     rd(m);  
  53.     int u,v;  
  54.     while(m--)  
  55.     {  
  56.         rd2(u,v);  
  57.         u--;v--;  
  58.         cost[u][v]=cost[v][u]=0;  
  59.     }  
  60.     printf("%d\n",Prim(cost,n));  
  61.     return 0;  
  62. }  

E 有n个节点,每个节点都有一个权值,然后给出任意两个节点之间的距离,要在两个节点之间连边,使得这n个节点联通,连边的代价除了两点之间边的距离之外还有两点各自的权值之和。在cost矩阵中,加入两个点的权值,然后求最小生成树。

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #define rd(x) scanf("%d",&x)  
  2. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  3. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  4. using namespace std;  
  5. typedef long long ll;  
  6. const int maxn=1004;  
  7. const int inf=0x3f3f3f3f;  
  8. int cost[maxn][maxn];  
  9. int lowc[maxn];  
  10. bool vis[maxn];  
  11. int val[maxn];  
  12. int n,m;  
  13.   
  14. int Prim(int cost[][maxn],int n)  
  15. {  
  16.     int ans=0;  
  17.     memset(vis,0,sizeof(vis));  
  18.     vis[0]=true;  
  19.     for(int i=1;i<n;i++)  
  20.         lowc[i]=cost[0][i];  
  21.     for(int i=1;i<n;i++)//寻找这么多次  
  22.     {  
  23.         int p=-1,minc=inf;  
  24.         for(int j=0;j<n;j++)  
  25.         {  
  26.             if(minc>lowc[j]&&!vis[j])  
  27.             {  
  28.                 minc=lowc[j];  
  29.                 p=j;  
  30.             }  
  31.         }  
  32.         vis[p]=1;  
  33.         ans+=minc;  
  34.         for(int j=0;j<n;j++)  
  35.         {  
  36.             if(!vis[j]&&lowc[j]>cost[p][j])  
  37.                 lowc[j]=cost[p][j];  
  38.         }  
  39.     }  
  40.     return ans;  
  41. }  
  42.   
  43.   
  44. int main()  
  45. {  
  46.     int t;rd(t);  
  47.     while(t--)  
  48.     {  
  49.         rd(n);  
  50.         memset(cost,inf,sizeof(cost));  
  51.         for(int i=0;i<n;i++)  
  52.             rd(val[i]);  
  53.         for(int i=0;i<n;i++)  
  54.             for(int j=0;j<n;j++)  
  55.         {  
  56.             rd(cost[i][j]);  
  57.             cost[i][j]+=val[i]+val[j];  
  58.         }  
  59.         printf("%d\n",Prim(cost,n));  
  60.     }  
  61.     return 0;  
  62. }  

F 给出N个长度为7的字符串,两个字符串之间定义距离为 两个字符串每个位置字母不同的个数,一个字符串可以生成另一个字符串,代价为两个字符串的距离,问这n个字符串最小的代价。  把任意两个字符串之间的距离求出来,然后进行最小生成树。

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #define rd(x) scanf("%d",&x)  
  2. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  3. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  4. using namespace std;  
  5. typedef long long ll;  
  6. const int maxn=2002;  
  7. const int inf=0x3f3f3f3f;  
  8. int cost[maxn][maxn];  
  9. int lowc[maxn];  
  10. bool vis[maxn];  
  11. string str[maxn];  
  12. int n;  
  13.   
  14. int cal(int i,int j)  
  15. {  
  16.     int cnt=0;  
  17.     for(int k=0;k<7;k++)  
  18.         if(str[i][k]!=str[j][k])  
  19.         cnt++;  
  20.     return cnt;  
  21. }  
  22.   
  23. int Prim(int cost[][maxn],int n)  
  24. {  
  25.     int ans=0;  
  26.     memset(vis,0,sizeof(vis));  
  27.     vis[0]=1;  
  28.     for(int i=1;i<n;i++)  
  29.         lowc[i]=cost[0][i];  
  30.     for(int i=1;i<n;i++)  
  31.     {  
  32.         int minc=inf,p=-1;  
  33.         for(int j=0;j<n;j++)  
  34.         {  
  35.             if(!vis[j]&&minc>lowc[j])  
  36.             {  
  37.                 minc=lowc[j];  
  38.                 p=j;  
  39.             }  
  40.         }  
  41.         vis[p]=1;  
  42.         ans+=minc;  
  43.         for(int j=0;j<n;j++)  
  44.         {  
  45.             if(!vis[j]&&lowc[j]>cost[p][j])  
  46.                 lowc[j]=cost[p][j];  
  47.         }  
  48.   
  49.     }  
  50.     return ans;  
  51. }  
  52.   
  53.   
  54. int main()  
  55. {  
  56.     while(rd(n)!=EOF&&n)  
  57.     {  
  58.         for(int i=0;i<n;i++)  
  59.             cin>>str[i];  
  60.         memset(cost,inf,sizeof(cost));  
  61.         for(int i=0;i<n;i++)  
  62.             for(int j=i+1;j<n;j++)  
  63.         {  
  64.             int w=cal(i,j);  
  65.             if(w<cost[i][j])  
  66.                 cost[i][j]=cost[j][i]=w;  
  67.         }  
  68.         printf("The highest possible quality is 1/%d.\n",Prim(cost,n));  
  69.   
  70.     }  
  71.     return 0;  
  72. }  

G 题意为有N个部落以及它们的坐标,然后有P个卫星,如果两个部落都有一个卫星的话,那么这两个部落无论距离多远都能通信,否则,两个部落只能依靠无线电通信,条件是只有两个部落的距离不超过D,两个部落才能通信,求最小的D,使得这N个部落都能通信。也就是在这N个部落里面找N-1条边,使得他们相互连通,P个卫星肯定是放在距离最大的村庄上,这样省去了P-1条边,所以我们只要再找N-1-(P-1)条边就好了,要求最小的D,也就是求这N-1-(P-1)条边里面的最大边的值。

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #define rd(x) scanf("%d",&x)  
  2. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  3. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  4. using namespace std;  
  5. typedef long long ll;  
  6. const int maxn=510;  
  7. const double inf=100000000.0;  
  8. double cost[maxn][maxn];  
  9. double lowc[maxn];  
  10. bool vis[maxn];  
  11. double edge[maxn];  
  12.   
  13. struct Point  
  14. {  
  15.     double x,y;  
  16.     void input()  
  17.     {  
  18.         scanf("%lf%lf",&x,&y);  
  19.     }  
  20.     double distance(Point p)  
  21.     {  
  22.         return hypot(x-p.x,y-p.y);  
  23.     }  
  24. }point[maxn];  
  25. int n,P;  
  26.   
  27. double Prim(double cost[][maxn],int n)  
  28. {  
  29.     memset(vis,0,sizeof(vis));  
  30.     vis[0]=1;  
  31.     for(int i=1;i<n;i++)  
  32.         lowc[i]=cost[0][i];  
  33.     int cnt=0;  
  34.     for(int i=1;i<n;i++)  
  35.     {  
  36.         double minc=inf;  
  37.         int p=-1;  
  38.         for(int j=0;j<n;j++)  
  39.         {  
  40.             if(!vis[j]&&minc>lowc[j])  
  41.             {  
  42.                 minc=lowc[j];  
  43.                 p=j;  
  44.             }  
  45.         }  
  46.         edge[cnt++]=minc;  
  47.         vis[p]=1;  
  48.         for(int j=0;j<n;j++)  
  49.         {  
  50.             if(!vis[j]&&lowc[j]>cost[p][j])  
  51.                 lowc[j]=cost[p][j];  
  52.         }  
  53.     }  
  54.     sort(edge,edge+cnt);//别忘了排序  
  55.     return edge[cnt-P];  
  56. }  
  57.   
  58. int main()  
  59. {  
  60.     int t;rd(t);  
  61.     while(t--)  
  62.     {  
  63.         rd2(P,n);  
  64.         for(int i=0;i<n;i++)  
  65.             point[i].input();  
  66.         for(int i=0;i<n;i++)  
  67.             for(int j=0;j<n;j++)  
  68.             cost[i][j]=inf;  
  69.         for(int i=0;i<n;i++)  
  70.             for(int j=0;j<n;j++)  
  71.         {  
  72.             double dis=point[i].distance(point[j]);  
  73.             if(dis<cost[i][j])  
  74.                 cost[i][j]=cost[j][i]=dis;  
  75.         }  
  76.         printf("%.2f\n",Prim(cost,n));  
  77.     }  
  78.     return 0;  
  79. }  

H 给定n个节点以及这n个节点的坐标,另外给出了m条已经现有的边,求要使这n个点连通,还需要建多少边,输出需要建边的两个端点编号。和上面有个题差不多,也是把给出的边的权值设置为0,然后pre[i]表示i节点所在边的另一个节点,最小生成树选择一条边以后,输出pre[p], p 就可以了。为了避免已经存在的边输出,判断一下是否cost[i][j] >0。因为刚才已存在的边已经赋值为0了。

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #define rd(x) scanf("%d",&x)  
  2. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  3. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  4. using namespace std;  
  5. typedef long long ll;  
  6. const int maxn=1000;  
  7. const int inf=0x3f3f3f3f;  
  8. bool vis[maxn];  
  9. int cost[maxn][maxn];  
  10. int lowc[maxn];  
  11. int pre[maxn];  
  12. int n,m;  
  13.   
  14. struct Point  
  15. {  
  16.     int x,y;  
  17.     int distance(Point p)  
  18.     {  
  19.         return (x-p.x)*(x-p.x)+(y-p.y)*(y-p.y);  
  20.     }  
  21. }point[maxn];  
  22.   
  23. void Prim()  
  24. {  
  25.     memset(vis,0,sizeof(vis));  
  26.     for(int i=1;i<n;i++)  
  27.     {  
  28.         lowc[i]=cost[0][i];  
  29.         pre[i]=0;  
  30.     }  
  31.     vis[0]=1;int p=-1;  
  32.     for(int i=1;i<n;i++)  
  33.     {  
  34.         int minc=inf;  
  35.   
  36.         for(int j=0;j<n;j++)  
  37.         {  
  38.             if(!vis[j]&&minc>lowc[j])  
  39.             {  
  40.                 minc=lowc[j];  
  41.                 p=j;  
  42.             }  
  43.         }  
  44.         vis[p]=1;  
  45.         if(cost[pre[p]][p])  
  46.             printf("%d %d\n",pre[p]+1,p+1);  
  47.         for(int j=0;j<n;j++)  
  48.         {  
  49.             if(lowc[j]>cost[p][j]&&!vis[j])  
  50.             {  
  51.                 lowc[j]=cost[p][j];  
  52.                 pre[j]=p;  
  53.             }  
  54.         }  
  55.     }  
  56. }  
  57.   
  58. int main()  
  59. {  
  60.         rd(n);  
  61.         memset(cost,inf,sizeof(cost));  
  62.         for(int i=0;i<n;i++)  
  63.             rd2(point[i].x,point[i].y);  
  64.         for(int i=0;i<n;i++)  
  65.             for(int j=i+1;j<n;j++)  
  66.         {  
  67.             int dis=point[i].distance(point[j]);  
  68.             if(cost[i][j]>dis)  
  69.                 cost[i][j]=cost[j][i]=dis;  
  70.         }  
  71.         rd(m);  
  72.         int u,v;  
  73.         while(m--)  
  74.         {  
  75.             rd2(u,v);  
  76.             u--;v--;  
  77.             cost[u][v]=cost[v][u]=0;  
  78.         }  
  79.         Prim();  
  80.     return 0;  
  81. }  
I 裸的最小生成树

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. const int maxn=5010;  
  2. int parent[110];  
  3. int n;  
  4.   
  5. struct Node  
  6. {  
  7.     int from,to,edge;  
  8. }node[maxn];  
  9.   
  10. void init(int n)  
  11. {  
  12.     for(int i=1;i<=n;i++)  
  13.         parent[i]=i;  
  14. }  
  15.   
  16. int find(int x)  
  17. {  
  18.     return parent[x]==x?x:find(parent[x]);  
  19. }  
  20.   
  21. bool cmp(Node a,Node b)  
  22. {  
  23.     if(a.edge<b.edge)  
  24.         return true;  
  25.     return false;  
  26. }  
  27.   
  28. int main()  
  29. {  
  30.     while(scanf("%d",&n)!=EOF)  
  31.     {  
  32.         int m=1;  
  33.         int len;  
  34.         for(int i=1;i<=n;i++)  
  35.             for(int j=1;j<=n;j++)  
  36.             {  
  37.                 scanf("%d",&len);  
  38.                 if(i<j)  
  39.                 {  
  40.                     int temp=m;  
  41.                     node[temp].from=i;  
  42.                     node[temp].to=j;  
  43.                     node[temp].edge=len;  
  44.                     m++;  
  45.                 }  
  46.             }  
  47.         init(n);  
  48.         m=n*(n-1)/2;  
  49.         len=0;  
  50.         sort(node+1,node+1+m,cmp);  
  51.         for(int i=1;i<=m;i++)  
  52.         {  
  53.             int x=find(node[i].from);  
  54.             int y=find(node[i].to);  
  55.             if(x==y)  
  56.                 continue;  
  57.             else  
  58.             {  
  59.                 len+=node[i].edge;  
  60.                 parent[x]=y;  
  61.             }  
  62.         }  
  63.         printf("%d\n",len);  
  64.     }  
  65.     return 0;  
  66. }  

J 在一个迷宫里面#代表不可走,空白可走,存在字母一个‘S' 和多个’A‘ ,要从S出发找到所有的A,可以从S出发分成多路去找A,问最少的步数和。也就是求最小生成树,节点为S和A,需要知道任意两个节点的最短距离,因为对每个点都用bfs,找出任意两个点之间的最短距离,然后使用最小生成树就可以了。 注意:输入格式,输入迷宫的大小n*m的时候很坑,要使用字符串格式...

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #define rd(x) scanf("%d",&x)  
  2. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  3. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  4. using namespace std;  
  5. typedef long long ll;  
  6. const int maxn=110;  
  7. const int inf=0x3f3f3f3f;  
  8. int cost[maxn][maxn];  
  9. int lowc[maxn];  
  10. bool vis[maxn][maxn];  
  11. int tot;  
  12. char mp[60][60];  
  13. int n,m;  
  14. int dx[4]={-1,1,0,0};  
  15. int dy[4]={0,0,1,-1};  
  16.   
  17. struct Point  
  18. {  
  19.     int i,j;  
  20. }point[maxn];  
  21.   
  22. void BFS(int from,int x,int y)  
  23. {  
  24.     memset(vis,0,sizeof(vis));  
  25.     int step[maxn][maxn];  
  26.     step[x][y]=0;  
  27.     vis[x][y]=1;  
  28.     queue<Point>q;  
  29.     Point a;  
  30.     a.i=x;a.j=y;  
  31.     q.push(a);  
  32.     while(!q.empty())  
  33.     {  
  34.         Point first=q.front();  
  35.         q.pop();  
  36.         for(int i=0;i<4;i++)  
  37.         {  
  38.             int newx=first.i+dx[i];  
  39.             int newy=first.j+dy[i];  
  40.             if(mp[newx][newy]!='#'&&!vis[newx][newy]&&newx>=0&&newx<n&&newy>=0&&newy<m)  
  41.             {  
  42.                 a.i=newx;a.j=newy;  
  43.                 vis[newx][newy]=1;  
  44.                 q.push(a);  
  45.                 step[newx][newy]=step[first.i][first.j]+1;  
  46.             }  
  47.         }  
  48.     }  
  49.     for(int i=0;i<tot;i++)  
  50.     {  
  51.         cost[from][i]=step[point[i].i][point[i].j];  
  52.     }  
  53. }  
  54.   
  55. int Prime(int cost[][maxn],int n)  
  56. {  
  57.     bool vis[maxn];  
  58.     int ans=0;  
  59.     memset(vis,0,sizeof(vis));  
  60.     vis[0]=1;  
  61.     for(int i=1;i<tot;i++)  
  62.         lowc[i]=cost[0][i];  
  63.     for(int i=1;i<n;i++)  
  64.     {  
  65.         int minc=inf,p=-1;  
  66.         for(int j=0;j<n;j++)  
  67.         {  
  68.             if(!vis[j]&&minc>lowc[j])  
  69.             {  
  70.                 p=j;  
  71.                 minc=lowc[j];  
  72.             }  
  73.         }  
  74.         ans+=minc;  
  75.         vis[p]=1;  
  76.         for(int j=0;j<n;j++)  
  77.         {  
  78.             if(!vis[j]&&lowc[j]>cost[p][j])  
  79.                 lowc[j]=cost[p][j];  
  80.         }  
  81.     }  
  82.     return ans;  
  83. }  
  84.   
  85.   
  86.   
  87. int main()  
  88. {  
  89.     int t;rd(t);  
  90.     getchar();  
  91.     while(t--)  
  92.     {  
  93.         gets(mp[0]);  
  94.         sscanf(mp[0],"%d%d",&m,&n);//这里的格式  
  95.         tot=1;  
  96.         for(int i=0;i<n;i++)  
  97.         {  
  98.             gets(mp[i]);  
  99.             int len=strlen(mp[i]);  
  100.             for(int k=0;k<len;k++)  
  101.             {  
  102.                 if(mp[i][k]=='A')  
  103.                     point[tot].i=i,point[tot++].j=k;  
  104.                 else if(mp[i][k]=='S')  
  105.                     point[0].i=i,point[0].j=k;  
  106.             }  
  107.         }  
  108.         //construct cost[][]  
  109.         memset(cost,inf,sizeof(cost));  
  110.         for(int i=0;i<tot;i++)  
  111.             BFS(i,point[i].i,point[i].j);  
  112.         /* 
  113.         for(int i=0;i<tot;i++) 
  114.         { 
  115.             for(int j=0;j<tot;j++) 
  116.                 cout<<cost[i][j]<<"       "; 
  117.                 cout<<endl; 
  118.         } 
  119.         */  
  120.         //进行prim  
  121.         printf("%d\n",Prime(cost,tot));  
  122.     }  
  123.     return 0;  
  124. }  

K 次小生成树,如果最小生成树唯一的话,输出最小权值,否则输出not unique。

http://blog.chinaunix.net/uid-25324849-id-2182922.html
次小生成树
求最小生成树时,用maxval[i][j],表示最小生成树中i到j路径中的最大边权
求完后,直接枚举所有不在最小生成树中的边(比如该边的两端是i,j,
然后替换掉路径i,j中最大边权的边,更新答案
点的编号从0开始。
为什么可以替换、
求完最小生成树后,从i到j有路径,那么路径上的点两两可以相互到达,如果去掉最大边
,那么该路径就切成了两部分,而加入不在最小生成树的一条边(比如该边地两端是i,j)
,那么又把这两部分重新串起来了,重新变得两两可以相互到达。

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #define rd(x) scanf("%d",&x)  
  2. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  3. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  4. using namespace std;  
  5. typedef long long ll;  
  6. const int maxn=110;  
  7. const int inf=0x3f3f3f3f;  
  8. bool vis[maxn];  
  9. int lowc[maxn];  
  10. int pre[maxn];  
  11. int cost[maxn][maxn];  
  12. int maxval[maxn][maxn];  
  13. bool used[maxn][maxn];  
  14.   
  15. int Prim(int cost[][maxn],int n)  
  16. {  
  17.     int ans=0;  
  18.     memset(vis,0,sizeof(vis));  
  19.     memset(maxval,0,sizeof(maxval));  
  20.     memset(used,0,sizeof(used));  
  21.     vis[0]=true;  
  22.     pre[0]=-1;  
  23.     for(int i=1;i<n;i++)  
  24.     {  
  25.         lowc[i]=cost[0][i];  
  26.         pre[i]=0;  
  27.     }  
  28.     lowc[0]=0;  
  29.     for(int i=1;i<n;i++)  
  30.     {  
  31.         int minc=inf,p=-1;  
  32.         for(int j=0;j<n;j++)  
  33.         {  
  34.             if(!vis[j]&&minc>lowc[j])  
  35.             {  
  36.                 minc=lowc[j];  
  37.                 p=j;  
  38.             }  
  39.         }  
  40.         if(minc==inf)  
  41.             return -1;  
  42.         ans+=minc;  
  43.         vis[p]=true;  
  44.         used[p][pre[p]]=used[pre[p]][p]=true;  
  45.         for(int j=0;j<n;j++)  
  46.         {  
  47.             if(vis[j])  
  48.                 maxval[j][p]=maxval[p][j]=max(maxval[j][pre[p]],lowc[p]);  
  49.             //为什么这么写,vis[j]代表那么节点已经访问过了,该条边是不能加的,有没有边都没关系,否则成了环,  
  50.             //那么在路径j->p中,j是路径的起点,p就是路径的终点,而maxval[j][pre[p]],就是起点j到p的上一个节点  
  51.             //组成的路径的最大边权值,lowc[p],则是带有p的那一边的权值,二者最大值,就是路径j->p的最大权值  
  52.             //比如 1->2->3->4-------->1,虚线代表有边或者没有边都行,那么此时p=4,j=1, pre[p]=3,  
  53.             //maxval[j][pre[p]]=maxval[1][3],也就是路径1到3上的最大边的权值,lowc[4]则是3到4上权值,二者的最大值  
  54.             //则是路径1->4的最大边的权值。  
  55.             if(!vis[j]&&lowc[j]>cost[p][j])  
  56.             {  
  57.                 lowc[j]=cost[p][j];  
  58.                 pre[j]=p;  
  59.             }  
  60.         }  
  61.     }  
  62.     return ans;  
  63. }  
  64.   
  65. int ans;//保存最小生成树的值  
  66.   
  67. int smst(int cost[][maxn],int n)//次小生成树  
  68. {  
  69.     int minc=inf;  
  70.     for(int i=0;i<n;i++)  
  71.         for(int j=i+1;j<n;j++)  
  72.     {  
  73.         if(cost[i][j]!=inf&&!used[i][j])//i,j之间有边,且该边没有在最小生成树中  
  74.         {  
  75.             minc=min(minc,ans+cost[i][j]-maxval[i][j]);//用该边替换最小生成树中i,j路径中的最大边  
  76.         }  
  77.     }  
  78.     if(minc==inf)  
  79.         return -1;  
  80.     return minc;  
  81. }  
  82. int n,m;  
  83.   
  84. int main()  
  85. {  
  86.     int t;rd(t);  
  87.     while(t--)  
  88.     {  
  89.         rd2(n,m);  
  90.         memset(cost,inf,sizeof(cost));  
  91.         int u,v,w;  
  92.         while(m--)  
  93.         {  
  94.             rd3(u,v,w);  
  95.             u--;  
  96.             v--;  
  97.             if(w<cost[u][v])  
  98.                 cost[u][v]=cost[v][u]=w;  
  99.         }  
  100.         ans=Prim(cost,n);  
  101.         if(ans==smst(cost,n))  
  102.             printf("Not Unique!\n");  
  103.         else  
  104.             printf("%d\n",ans);  
  105.     }  
  106.     return 0;  
  107. }  

L 裸最小生成树

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #define rd(x) scanf("%d",&x)  
  2. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  3. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  4. using namespace std;  
  5. typedef long long ll;  
  6. const int maxn=110;  
  7. const int maxm=5000;  
  8.   
  9. struct Edge  
  10. {  
  11.     int u,v,w;  
  12. }edge[maxm];  
  13. int tot;//边的个数  
  14. int parent[maxn];  
  15.   
  16. void addege(int u,int v,int w)  
  17. {  
  18.     edge[tot].u=u;  
  19.     edge[tot].v=v;  
  20.     edge[tot++].w=w;  
  21. }  
  22.   
  23. void init(int n)  
  24. {  
  25.     tot=0;  
  26.     for(int i=0;i<=n;i++)  
  27.         parent[i]=i;  
  28. }  
  29.   
  30. int find(int x)  
  31. {  
  32.     if(parent[x]==x)  
  33.         return x;  
  34.     parent[x]=find(parent[x]);  
  35.     return parent[x];  
  36. }  
  37.   
  38. bool cmp(Edge a,Edge b)  
  39. {  
  40.     return a.w<b.w;  
  41. }  
  42.   
  43. int n;  
  44.   
  45. int kruskal(int n)  
  46. {  
  47.     sort(edge,edge+tot,cmp);  
  48.     int cnt=0;//计算加入的边数  
  49.     int ans=0;  
  50.     for(int i=0;i<tot;i++)  
  51.     {  
  52.         int u=edge[i].u;  
  53.         int v=edge[i].v;  
  54.         int w=edge[i].w;  
  55.         int t1=find(u);  
  56.         int t2=find(v);  
  57.         if(t1!=t2)  
  58.         {  
  59.             ans+=w;  
  60.             parent[t1]=t2;  
  61.             cnt++;  
  62.         }  
  63.         if(cnt==n-1)  
  64.             break;  
  65.     }  
  66.     if(cnt<n-1)  
  67.         return -1;//不连通  
  68.     else  
  69.         return ans;  
  70. }  
  71.   
  72. int main()  
  73. {  
  74.     while(rd(n)!=EOF&&n)  
  75.     {  
  76.         init(n);  
  77.         int u,v,w;  
  78.         for(int i=1;i<=n*(n-1)/2;i++)  
  79.         {  
  80.             rd3(u,v,w);  
  81.             addege(u,v,w);  
  82.         }  
  83.         printf("%d\n",kruskal(n));  
  84.     }  
  85.     return 0;  
  86. }  

N 同裸,浮点数。

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include <iostream>  
  2. #include <stdio.h>  
  3. #include <algorithm>  
  4. #include <string.h>  
  5. #include <stdlib.h>  
  6. #include <cmath>  
  7. #include <iomanip>  
  8. #include <vector>  
  9. #include <set>  
  10. #include <map>  
  11. #include <stack>  
  12. #include <queue>  
  13. #include <cctype>  
  14. #define rd(x) scanf("%d",&x)  
  15. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  16. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  17. using namespace std;  
  18. typedef long long ll;  
  19. const int maxn=110;  
  20.   
  21. struct Point  
  22. {  
  23.     double x,y;  
  24.     double distance(Point p)  
  25.     {  
  26.         return hypot(x-p.x,y-p.y);  
  27.     }  
  28. }point[maxn];  
  29.   
  30. const double inf=100000.0;  
  31. bool vis[maxn];  
  32. double lowc[maxn];  
  33. double cost[maxn][maxn];  
  34.   
  35. double Prim(double cost[][maxn],int n)  
  36. {  
  37.     double ans=0;  
  38.     memset(vis,0,sizeof(vis));  
  39.     vis[0]=true;  
  40.     for(int i=1;i<n;i++)  
  41.         lowc[i]=cost[0][i];  
  42.     for(int i=1;i<n;i++)  
  43.     {  
  44.         double minc=inf;  
  45.         int p=-1;  
  46.         for(int j=0;j<n;j++)  
  47.         {  
  48.             if(!vis[j]&&minc>lowc[j])  
  49.             {  
  50.                 minc=lowc[j];  
  51.                 p=j;  
  52.             }  
  53.         }  
  54.         if(minc==inf)  
  55.             return -1.0;  
  56.         ans+=minc;  
  57.         vis[p]=true;  
  58.         for(int j=0;j<n;j++)  
  59.             if(!vis[j]&&lowc[j]>cost[p][j])  
  60.             lowc[j]=cost[p][j];  
  61.     }  
  62.     return ans;  
  63. }  
  64. int n;  
  65.   
  66. int main()  
  67. {  
  68.     int t;rd(t);  
  69.     while(t--)  
  70.     {  
  71.         rd(n);  
  72.         for(int i=0;i<n;i++)  
  73.             scanf("%lf%lf",&point[i].x,&point[i].y);  
  74.         for(int i=0;i<n;i++)  
  75.         {  
  76.             for(int j=0;j<n;j++)  
  77.                 cost[i][j]=inf;  
  78.         }  
  79.         /* 
  80.         for(int i=0;i<n;i++) 
  81.         { 
  82.             for(int j=0;j<n;j++) 
  83.                 cout<<cost[i][j]<<" "; 
  84.             cout<<endl; 
  85.         } 
  86.         */  
  87.         for(int i=0;i<n;i++)  
  88.         {  
  89.             for(int j=i+1;j<n;j++)  
  90.             {  
  91.                 double dis=point[i].distance(point[j]);  
  92.                 if(dis<cost[i][j]&&dis>=10&&dis<=1000)  
  93.                 {  
  94.                     cost[i][j]=dis;  
  95.                     cost[j][i]=dis;  
  96.                 }  
  97.             }  
  98.         }  
  99.         double ans=Prim(cost,n);  
  100.         if(ans==-1.0)  
  101.             printf("oh!\n");  
  102.         else  
  103.             printf("%.1f\n",ans*100);  
  104.     }  
  105.     return 0;  
0 0
原创粉丝点击