度限制最小生成树 POJ 1639 贪心+DFS+prim

很好的解题报告:

http://blog.csdn.net/new_c_yuer/article/details/6365689

注意两点:

1.预处理环中权值最大的边····

2.可以把去掉度限制后的点看成是连通的,权值为无穷远的点也看做是连通的,反正后面肯定会替换出来的····

我的代码没有预处理出权值最大的边,但是第2点事做到了的,这样便于代码的实现·····

贴代码:

  1 #include <cstdio>
  2 #include <iostream>
  3 #include <map>
  4 #include <string>
  5 #include <algorithm>
  6 #define INF 0x3f3f3f3f
  7 #define N 505
  8 using namespace std;
  9 map<string,int> ma;
 10 map<string,int>::iterator it;
 11 int n,k;//点的个数,度数限制
 12 bool flag;
 13 long long int ans;//最后的结果
 14 bool in[N][N],vis[N];//加入最小生成树中的边
 15 int edge[N][N],pre[N], next[N],lowcost[N];//边,确定哪些边被加入了最小生成树中,存环中的边,求最小生成树
 16 int Find(char c[])
 17 {
 18     it = ma.find(c);
 19     if(it != ma.end())
 20         return it->second;
 21     ma[c] = ++n;
 22     return n;
 23 }
 24 //用prim函数求一次去掉度限制的点后的最小生成树
 25 void prim()
 26 {
 27     lowcost[1] = -1;
 28     for(int i=2; i<=n; ++i)
 29     {
 30         lowcost[i] = edge[1][i];
 31         pre[i] = 1;
 32     }
 33     for(int i=2; i<=n; ++i)
 34     {
 35         int v;
 36         int minum=INF;
 37         for(int j=2; j<=n; ++j)
 38         {
 39             if(lowcost[j] != -1 && minum >= lowcost[j])
 40             {
 41                 minum = lowcost[j];
 42                 v = j;
 43             }
 44         }
 45         lowcost[v] = -1;
 46         ans += edge[v][pre[v]];
 47         in[v][pre[v]] = in[pre[v]][v] = 1;
 48         for(int j=2; j<=n; ++j)
 49         {
 50             if(lowcost[j] != -1 &&  lowcost[j] > edge[j][v] )
 51             {
 52                 lowcost[j] = edge[j][v];
 53                 pre[j] = v;
 54             }
 55         }
 56     }
 57 }
 58 //dfs找出环
 59 void dfs(int x)
 60 {
 61     if(x == 0)
 62     {
 63         flag = true;
 64         return;
 65     }
 66     vis[x] = 1;
 67     for(int i = n; i >= 0; --i)
 68     {
 69         if(in[x][i] && !vis[i] && !flag)
 70         {
 71             next[x] = i;
 72             dfs(i);
 73         }
 74     }
 75 }
 76 //找环上权值最大的边
 77 void findMax(int x,int &s,int &e,int &maxnum)
 78 {
 79     memset(vis,0,sizeof(vis));
 80     flag = false;
 81     dfs(x);
 82     maxnum = edge[0][x];
 83     int ne = x;
 84     while(next[ne] != 0)
 85     {
 86         if(edge[ne][next[ne]] > maxnum)
 87         {
 88             maxnum = edge[ne][next[ne]];
 89             s = ne;
 90             e = next[ne];
 91         }
 92         ne  = next[ne];
 93     }
 94 }
 95 //找度限制为k的最小生成树
 96 void kTree()
 97 {
 98     int minum = INF;
 99     int v;
100     for(int i=1; i<=n; ++i)
101     {
102         if(edge[0][i] < minum)
103         {
104             minum = edge[0][i];
105             v =  i;
106         }
107     }
108     in[v][0] = in[0][v] = 1;
109     ans += edge[0][v];
110     for(int t=1; t<k; ++t)
111     {
112         minum = INF;
113         v = -1;
114         int s,e,m;
115         for(int i=1; i<=n; ++i)
116         {
117             if(!in[0][i] && edge[0][i] < INF)
118             {
119                 int ss,ee,maxnum;
120                 findMax(i,ss,ee,maxnum);
121                 if(edge[0][i] - maxnum < minum)
122                 {
123                     minum = edge[0][i] - maxnum ;
124                     s = ss;
125                     e = ee;
126                     m = minum;
127                     v= i;
128                 }
129             }
130         }
131         if(v == -1) break;
132         if(minum >= 0 ) break;
133         in[0][v] = 1;
134         in[v][0] = 1;
135         in[s][e] = 0;
136         in[e][s] =0;
137         ans += minum;
138     }
139     printf("Total miles driven: %d\n",ans);
140 }
141 // 初始化输入
142 void initScan()
143 {
144     int m;
145     ma["Park"] = n;
146     scanf("%d",&m);
147     memset(edge,0x3f,sizeof(edge));
148     for(int i=0; i<m; ++i)
149     {
150         char a1[N],a2[N];
151         int u,v,w;
152         scanf("%s %s %d",a1,a2,&w);
153         u = Find(a1);
154         v = Find(a2);
155         edge[u][v] = w;
156         edge[v][u] = edge[u][v];
157     }
158     scanf("%d",&k);
159 }
160 int main()
161 {
162     initScan();
163     prim();
164     kTree();
165     return 0;
166 }
View Code

 

posted on 2013-08-10 16:38  allh123  阅读(187)  评论(0编辑  收藏  举报

导航