poj 3164 Command Network
#include<cstring> #include<cstdio> #include<cmath> #include<algorithm> using namespace std; #define maxn 120 #define INF 99999999999.0 int n,m; struct node { double x,y; } a[maxn]; inline double get_dis(node a,node b) { return sqrt((a.x - b.x)*(a.x - b.x)+(a.y - b.y)*(a.y - b.y)); } double map[maxn][maxn]; bool flag[maxn]; int pre[maxn]; void dfs(int x) { flag[x]=true; for(int i=1; i<=n; i++) if(!flag[i]&&map[x][i]!=INF) dfs(i); } bool check()//检查联通 { memset(flag,0,sizeof(flag)); dfs(1); for(int i=1; i<=n; i++) if(!flag[i])return false; return true; } double solve() { memset(flag,0,sizeof(flag));//flag是true的点是被去掉的点 int i,j,k; double ans=0; while(1) { for(i=2; i<=n; i++) if(!flag[i]) { pre[i]=i; map[i][i]=INF; for(j=1; j<=n; j++) if(!flag[j]) { if(map[pre[i]][i]>map[j][i]) pre[i]=j; } } for(i=2; i<=n; i++) if(!flag[i]) { bool mark[maxn]; memset(mark,0,sizeof(mark)); for(j=i; j!=1&&!mark[j]; mark[j]=true,j=pre[j]); //寻找环,返回在环内的一点(注意从i出发能找到换不代表n在环内) if(j==1)continue; i=j; ans+=map[pre[i]][i]; for(j=pre[i]; j!=i; j=pre[j]) { ans+=map[pre[j]][j]; flag[j]=true; } for(j=1; j<=n; j++)if(!flag[j]&&map[j][i]!=INF) map[j][i]-=map[pre[i]][i]; for(j=pre[i]; j!=i; j=pre[j]) { for(k=1; k<=n; k++)if(!flag[k]&&map[j][k]!=INF) map[i][k]=min(map[i][k],map[j][k]); for(k=1; k<=n; k++)if(!flag[k]&&map[k][j]!=INF) map[k][i]=min(map[k][i],map[k][j]-map[pre[j]][j]); } break; } if(i>n)//说明没有环了。 { for(j=2; j<=n; j++)if(!flag[j]) ans+=map[pre[j]][j]; return ans; } } } int main() { int i,j,x,y; while(scanf("%d%d",&n,&m)!=-1) { for(i=1; i<=n; i++) scanf("%lf%lf",&a[i].x,&a[i].y); for(i=1; i<=n; i++) for(j=1; j<=n; j++) map[i][j]=INF; for(i=1; i<=m; i++) { scanf("%d%d",&x,&y); if(x==y)continue;//消除自环 map[x][y]=get_dis(a[x],a[y]); } if(!check())//检查有向图是否联通 { printf("poor snoopy\n"); } else { printf("%.2lf\n",solve()); } } } /* 算法核心需要三个步骤: ①找出每个点最小的入边in[v],如果有除根节点之外的点没有入边,显然无解。 ②累加出上面所有点的最小入边的值。 找出图中的环,如果没有环,终止,返回解;否则,缩点,转入第三步。 ③重新构图。令每条点v的入边w的值都减去in[v]。转入第一步。 不固定根 作法是,新设置一个人工点,向每一个顶点连一条边(称为"另类边"),权值至少比原图所有边之和还大1。 然后,以改人工点为root,求一次最小树形图。并在过程中记录使用过的边(即每次找出的最小入边)。 如果使用的 "另类边" 的次数大于1,就是impossible.否则可以找出这条边,找出那个city即可。 因为要找最小的城市,所以,我们添加边的时候,按照城市依次添加边root-->城市i就好了。 */
2248. Channel Design
#include<cstring> #include<cstdio> #include<cmath> #include<algorithm> using namespace std; #define maxn 102 #define INF 99999999 int n,m; int map[maxn][maxn]; bool flag[maxn]; int pre[maxn]; void dfs(int x) { flag[x]=true; for(int i=1; i<=n; i++) if(!flag[i]&&map[x][i]!=INF) dfs(i); } bool check()//检查联通 { memset(flag,0,sizeof(flag)); dfs(1); for(int i=1; i<=n; i++) if(!flag[i])return false; return true; } int solve() { memset(flag,0,sizeof(flag));//flag是true的点是被去掉的点 int i,j,k; int ans=0; while(1) { for(i=2; i<=n; i++) if(!flag[i]) { pre[i]=i; map[i][i]=INF; for(j=1; j<=n; j++) if(!flag[j]) { if(map[pre[i]][i]>map[j][i]) pre[i]=j; } } for(i=2; i<=n; i++) if(!flag[i]) { bool mark[maxn]; memset(mark,0,sizeof(mark)); for(j=i; j!=1&&!mark[j]; mark[j]=true,j=pre[j]); //寻找环,返回在环内的一点(注意从i出发能找到换不代表n在环内) if(j==1)continue; i=j; ans+=map[pre[i]][i]; for(j=pre[i]; j!=i; j=pre[j]) { ans+=map[pre[j]][j]; flag[j]=true; } for(j=1; j<=n; j++)if(!flag[j]&&map[j][i]!=INF) map[j][i]-=map[pre[i]][i]; for(j=pre[i]; j!=i; j=pre[j]) { for(k=1; k<=n; k++)if(!flag[k]&&map[j][k]!=INF) map[i][k]=min(map[i][k],map[j][k]); for(k=1; k<=n; k++)if(!flag[k]&&map[k][j]!=INF) map[k][i]=min(map[k][i],map[k][j]-map[pre[j]][j]); } break; } if(i>n)//说明没有环了。 { for(j=2; j<=n; j++)if(!flag[j]) ans+=map[pre[j]][j]; return ans; } } } int main() { while(scanf("%d%d", &n ,&m) != EOF) { if(n == 0 && m == 0) break; for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) map[i][j]=INF; int x, y, z; for(int i = 1; i <= m; i++) { scanf("%d%d%d",&x, &y, &z); if(x == y) continue;//消除自环 map[x][y] = min(map[x][y], z); } if(!check()) { printf("impossible\n"); } else { printf("%d\n", solve()); } } return 0; } /* 算法核心需要三个步骤: ①找出每个点最小的入边in[v],如果有除根节点之外的点没有入边,显然无解。 ②累加出上面所有点的最小入边的值。 找出图中的环,如果没有环,终止,返回解;否则,缩点,转入第三步。 ③重新构图。令每条点v的入边w的值都减去in[v]。转入第一步。 不固定根 作法是,新设置一个人工点,向每一个顶点连一条边(称为"另类边"),权值至少比原图所有边之和还大1。 然后,以改人工点为root,求一次最小树形图。并在过程中记录使用过的边(即每次找出的最小入边)。 如果使用的 "另类边" 的次数大于1,就是impossible.否则可以找出这条边,找出那个city即可。 因为要找最小的城市,所以,我们添加边的时候,按照城市依次添加边root-->城市i就好了。 */
uva 11183 teen girl squad
#include<cstring> #include<cstdio> #include<cmath> #include<algorithm> using namespace std; #define maxn 1052 #define INF 99999999 int n,m; int map[maxn][maxn]; bool flag[maxn]; int pre[maxn]; void dfs(int x) { flag[x]=true; for(int i=1; i<=n; i++) if(!flag[i]&&map[x][i]!=INF) dfs(i); } bool check()//检查联通 { memset(flag,0,sizeof(flag)); dfs(1); for(int i=1; i<=n; i++) if(!flag[i])return false; return true; } int solve() { memset(flag,0,sizeof(flag));//flag是true的点是被去掉的点 int i,j,k; int ans=0; while(1) { for(i=2; i<=n; i++) if(!flag[i]) { pre[i]=i; map[i][i]=INF; for(j=1; j<=n; j++) if(!flag[j]) { if(map[pre[i]][i]>map[j][i]) pre[i]=j; } } for(i=2; i<=n; i++) if(!flag[i]) { bool mark[maxn]; memset(mark,0,sizeof(mark)); for(j=i; j!=1&&!mark[j]; mark[j]=true,j=pre[j]); //寻找环,返回在环内的一点(注意从i出发能找到换不代表n在环内) if(j==1)continue; i=j; ans+=map[pre[i]][i]; for(j=pre[i]; j!=i; j=pre[j]) { ans+=map[pre[j]][j]; flag[j]=true; } for(j=1; j<=n; j++)if(!flag[j]&&map[j][i]!=INF) map[j][i]-=map[pre[i]][i]; for(j=pre[i]; j!=i; j=pre[j]) { for(k=1; k<=n; k++)if(!flag[k]&&map[j][k]!=INF) map[i][k]=min(map[i][k],map[j][k]); for(k=1; k<=n; k++)if(!flag[k]&&map[k][j]!=INF) map[k][i]=min(map[k][i],map[k][j]-map[pre[j]][j]); } break; } if(i>n)//说明没有环了。 { for(j=2; j<=n; j++)if(!flag[j]) ans+=map[pre[j]][j]; return ans; } } } int main() { int T, cas = 1; scanf("%d", &T); while(T--) { scanf("%d%d", &n ,&m); if(n == 0 && m == 0) break; for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) map[i][j]=INF; int x, y, z; for(int i = 1; i <= m; i++) { scanf("%d%d%d",&x, &y, &z); x++; y++; if(x == y) continue;//消除自环 map[x][y] = min(map[x][y], z); } if(!check()) { printf("Case #%d: Possums!\n", cas++); } else { printf("Case #%d: %d\n", cas++, solve()); } } return 0; } /* 算法核心需要三个步骤: ①找出每个点最小的入边in[v],如果有除根节点之外的点没有入边,显然无解。 ②累加出上面所有点的最小入边的值。 找出图中的环,如果没有环,终止,返回解;否则,缩点,转入第三步。 ③重新构图。令每条点v的入边w的值都减去in[v]。转入第一步。 不固定根 作法是,新设置一个人工点,向每一个顶点连一条边(称为"另类边"),权值至少比原图所有边之和还大1。 然后,以改人工点为root,求一次最小树形图。并在过程中记录使用过的边(即每次找出的最小入边)。 如果使用的 "另类边" 的次数大于1,就是impossible.否则可以找出这条边,找出那个city即可。 因为要找最小的城市,所以,我们添加边的时候,按照城市依次添加边root-->城市i就好了。 */
hdu 2121 ice_cream's world ll
弄个虚拟根,代码不贴了,用的别人的模板