标签:uml res number ++i park text order like 停止
Time Limit: 5000MS | Memory Limit: 10000K | |
Total Submissions: 10742 | Accepted: 3885 |
10 Alphonzo Bernardo 32 Alphonzo Park 57 Alphonzo Eduardo 43 Bernardo Park 19 Bernardo Clemenzi 82 Clemenzi Park 65 Clemenzi Herb 90 Clemenzi Eduardo 109 Park Herb 24 Herb Eduardo 79 3
Total miles driven: 183
要求做一个最小生成树,限制条件:给定其中一个点限制其的度不超过 k (最小 k 度限制生成树)。
第一步,设被限制度数的节点为 v0 ,则在去除 v0 的情况下做最小生成树,可能得到若干个最小生成树(设有 m 棵树);容易想到,这写树必须通过 v0 来连接成一颗树。
第二步,从 v0 引出 m 条边分别连向 m 棵树,则此时得到一个最小 m 度限制生成树,若给定的 k 小于 m 则说明这不是连通图,无法做生成树。
第三步,最多找出 k-m 条 v0 的边去替换树上现有的边;当然,替换必须使树变小才合法。这一步是比较麻烦的,并且若直接枚举的话时间复杂度也较高。每次使用动态规划找出一条贡献最大的边,并替换进树中。直到找齐 k-m 条边、或无法找到合法边是停止。此时得到的就是最小 k 度限制生成树了。
思路如上十分清晰,可实现起来细节太多了,比较坑的是同一道题不能在不同的OJ AC。在多次调试之后我的代码总算征服了poj、uva、uvalive、scu,但 fzu 却迟迟不能AC。在纵观其他大佬的题解后,发现我的代码已经算强的了....
此题需要注意的是:输入是两点之间可能存在多条边,需要保留最小的边。
#include<iostream> #include<map> #include<cstring> #include<vector> #include<queue> #include<algorithm> #include<cstdio> #define READFILE freopen("D:\\in.txt","r",stdin); #define INF 1e9+7 using namespace std; class Edge { public: int u, v, w; Edge(int a=0, int b=0, int c=0):u(a), v(b), w(c) {} }; map<string, int> mp; vector<Edge> edges; Edge dp[105]; int m, n, k, md, grap[105][105], fa[105], mst[105][105], ans=0; bool cmp(Edge a, Edge b) { return a.w<b.w; } void Init() { memset(grap, -1, sizeof(grap));//-1不可达 memset(mst, 0, sizeof(mst)); mp.clear(); edges.clear(); n=1, md=0, ans=0, k=0; int u, v, w; mp["Park"]=1; string name1, name2; cin>>m; for(int i=0; i<m; ++i) { cin>>name1>>name2>>w; if(mp.find(name1)==mp.end()) mp[name1]=n++; if(mp.find(name2)==mp.end()) mp[name2]=n++; u=mp[name1], v=mp[name2]; edges.push_back(Edge(u, v, w)); if(grap[u][v]==-1) grap[u][v]=grap[v][u]=w; else grap[u][v]=grap[v][u]=min(grap[u][v], w); } cin>>k; } int Find(int x) { if(fa[x]!=x) return fa[x]=Find(fa[x]); return x; } void Union(int a, int b) { int x=Find(a); int y=Find(b); if(x!=y) fa[x]=y; } int Kruskal()//去除限制点生成md棵最小生成树 { int res=0; sort(edges.begin(), edges.end(), cmp); for(int i=0; i<=n; ++i) fa[i]=i; for(int i=0; i<edges.size(); ++i) { Edge& e=edges[i]; if(e.u==1 || e.v==1 || Find(e.u)==Find(e.v)) continue; Union(e.u, e.v); mst[e.u][e.v]=mst[e.v][e.u]=grap[e.u][e.v]; res+=grap[e.u][e.v]; } return res; } int mmst()//生成最小md度限制生成树 { int minw[25], minv[25], res=0; for(int i=0; i<=n; ++i) minw[i]=INF; for(int i=2; i<=n; ++i) if(grap[1][i]!=-1) { int x=Find(i); if(minw[x] > grap[1][i]) { minw[x]=grap[1][i]; minv[x]=i; } } for(int i=1; i<=n; ++i) if(minw[i]!=INF) { md++; mst[1][minv[i]]=mst[minv[i]][1]=1; res+=grap[1][minv[i]]; } return res; } void dfs(int x,int fa) { for(int i=2; i<=n; i++) if(mst[x][i] && i!=fa) { if(dp[i].w==-1) { if(grap[x][i]<dp[x].w) { dp[i].u=dp[x].u; dp[i].v=dp[x].v; dp[i].w=dp[x].w; } else dp[i].u=x,dp[i].v=i,dp[i].w=grap[x][i]; } dfs(i,x); } } int mkst() { int res=0; for(int i=md+1; i<=k; i++) { for(int j=0; j<=n; ++j) dp[j].w=-1; dp[1].w=-INF; for(int j=2; j<=n; j++) if(mst[1][j]) dp[j].w=-INF; dfs(1,-1); int t=0,minn=INF; for(int j=2; j<=n; j++) if(grap[1][j]!=-1&&grap[1][j]-dp[j].w<minn) { minn=grap[1][j]-dp[j].w; t=j; } if(minn>=0) break; mst[1][t]=mst[t][1]=1; int x=dp[t].u,y=dp[t].v; mst[x][y]=mst[y][x]=0; res+=minn; } return res; } int main() { //READFILE int t; t=1;//有的oj多组数据此处改为cin>>t即可 while(t--) { Init(); int ans1=Kruskal(); int ans2=mmst(); int ans3=mkst(); ans=ans1+ans2+ans3; cout<<"Total miles driven: "<<ans<<endl; if(t)cout<<endl; } return 0; }
poj1639,uva1537,uvalive2099,scu1622,fzu1761 Picnic Planning (最小限制生成树)
标签:uml res number ++i park text order like 停止
原文地址:http://www.cnblogs.com/xiepingfu/p/7327797.html