最小树形图(有向图)
GGS-DDU http://acm.hdu.edu.cn/showproblem.php?pid=4966
建图待补,先做模板了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstring> 3 #define mt(a,b) memset(a,b,sizeof(a)) 4 const int inf=0x3f3f3f3f; 5 class Directed_MST { ///最小树形图(有向图) 6 typedef int typec;///边权的类型 7 static const int ME=250010;///边的个数 8 static const int MV=550;///点的个数 9 struct E { 10 int u,v; 11 typec w; 12 } e[ME]; 13 int n,le,pre[MV],ID[MV],vis[MV]; 14 typec In[MV]; 15 public: 16 void init() { 17 le=0; 18 } 19 void add(int u,int v,typec w) { 20 e[le].u=u; 21 e[le].v=v; 22 e[le].w=w; 23 le++; 24 } 25 typec solve(int root,int tn) {///传入根和点的个数,点下标0开始 26 n=tn; 27 typec ret=0; 28 while(true) { 29 for(int i=0; i<n; i++) { 30 In[i]=inf; 31 } 32 for(int i=0; i<le; i++) { 33 int u=e[i].u; 34 int v=e[i].v; 35 if(e[i].w<In[v]&&u!=v) { 36 pre[v]=u; 37 In[v]=e[i].w; 38 } 39 } 40 for(int i=0; i<n; i++) { 41 if(i==root) continue; 42 if(In[i]==inf) return -1;///除了根以外有点没有入边,则根无法到达它 43 } 44 int cntnode=0;///找环 45 mt(ID,-1); 46 mt(vis,-1); 47 In[root]=0; 48 for(int i=0; i<n; i++) { ///标记每个环 49 ret+=In[i]; 50 int v=i; 51 while(vis[v]!=i&&ID[v]==-1&&v!=root) { 52 vis[v]=i; 53 v=pre[v]; 54 } 55 if(v!=root&&ID[v]==-1) { 56 for(int u=pre[v]; u!=v; u=pre[u]) { 57 ID[u]=cntnode; 58 } 59 ID[v]=cntnode++; 60 } 61 } 62 if(!cntnode) break;///无环 63 for(int i=0; i<n; i++) { 64 if(ID[i]==-1) { 65 ID[i]=cntnode++; 66 } 67 } 68 for(int i=0; i<le; i++) { ///缩点,重新标记 69 int v=e[i].v; 70 e[i].u=ID[e[i].u]; 71 e[i].v=ID[e[i].v]; 72 if(e[i].u!=e[i].v) { 73 e[i].w-=In[v]; 74 } 75 } 76 n=cntnode; 77 root=ID[root]; 78 } 79 return ret; 80 } 81 } gx; 82 int n,m,a[550],s[550]; 83 int main() { 84 while(~scanf("%d%d",&n,&m),n|m){ 85 for(int i=0;i<n;i++){ 86 scanf("%d",&a[i]); 87 a[i]++; 88 } 89 s[0]=0; 90 for(int i=0;i<n;i++){ 91 s[i+1]=a[i]+s[i]; 92 } 93 gx.init(); 94 for(int i=0;i<n;i++){ 95 for(int j=s[i+1]-1;j>s[i];j--){ 96 gx.add(j,j-1,0); 97 } 98 gx.add(s[n],s[i],0); 99 } 100 while(m--){ 101 int a,L1,b,L2,cost; 102 scanf("%d%d%d%d%d",&a,&L1,&b,&L2,&cost); 103 a--; 104 b--; 105 a=s[a]+L1; 106 b=s[b]+L2; 107 gx.add(a,b,cost); 108 } 109 printf("%d\n",gx.solve(s[n],s[n]+1)); 110 } 111 return 0; 112 }
Transfer water http://acm.hdu.edu.cn/showproblem.php?pid=4009
待补,测模板。可以变根的,用邻接表存的。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #define mt(a,b) memset(a,b,sizeof(a)) 5 using namespace std; 6 typedef __int64 LL; 7 const int inf=0x3f3f3f3f; 8 const int M=1024; 9 class Directed_MST { ///最小树形图(有向图) 10 typedef int typec;///边权的类型 11 static const int ME=M*M;///边的个数 12 static const int MV=M;///点的个数 13 struct E { 14 int u,v; 15 typec w; 16 } e[ME]; 17 int n,le,pre[MV],ID[MV],vis[MV]; 18 typec In[MV]; 19 public: 20 void init() { 21 le=0; 22 } 23 void add(int u,int v,typec w) { 24 e[le].u=u; 25 e[le].v=v; 26 e[le].w=w; 27 le++; 28 } 29 typec solve(int root,int tn) {///传入根和点的个数,点下标0开始 30 n=tn; 31 typec ret=0; 32 while(true) { 33 for(int i=0; i<n; i++) { 34 In[i]=inf; 35 } 36 for(int i=0; i<le; i++) { 37 int u=e[i].u; 38 int v=e[i].v; 39 if(e[i].w<In[v]&&u!=v) { 40 pre[v]=u; 41 In[v]=e[i].w; 42 } 43 } 44 for(int i=0; i<n; i++) { 45 if(i==root) continue; 46 if(In[i]==inf) return -1;///除了根以外有点没有入边,则根无法到达它 47 } 48 int cntnode=0;///找环 49 mt(ID,-1); 50 mt(vis,-1); 51 In[root]=0; 52 for(int i=0; i<n; i++) { ///标记每个环 53 ret+=In[i]; 54 int v=i; 55 while(vis[v]!=i&&ID[v]==-1&&v!=root) { 56 vis[v]=i; 57 v=pre[v]; 58 } 59 if(v!=root&&ID[v]==-1) { 60 for(int u=pre[v]; u!=v; u=pre[u]) { 61 ID[u]=cntnode; 62 } 63 ID[v]=cntnode++; 64 } 65 } 66 if(!cntnode) break;///无环 67 for(int i=0; i<n; i++) { 68 if(ID[i]==-1) { 69 ID[i]=cntnode++; 70 } 71 } 72 for(int i=0; i<le; i++) { ///缩点,重新标记 73 int v=e[i].v; 74 e[i].u=ID[e[i].u]; 75 e[i].v=ID[e[i].v]; 76 if(e[i].u!=e[i].v) { 77 e[i].w-=In[v]; 78 } 79 } 80 n=cntnode; 81 root=ID[root]; 82 } 83 return ret; 84 } 85 } gx; 86 int ha[M],hb[M],hc[M]; 87 int X,Y,Z; 88 int dist(int i, int j) { 89 int ret = abs(ha[i] - ha[j]) + abs(hb[i] - hb[j]) + abs(hc[i] - hc[j]); 90 ret *= Y; 91 if (hc[i] < hc[j]) ret += Z; 92 return ret; 93 } 94 int main(){ 95 int n; 96 while(~scanf("%d%d%d%d",&n,&X,&Y,&Z),n+X+Y+Z) { 97 n++; 98 gx.init(); 99 for (int i = 2; i <= n; i++) scanf("%d %d %d", &ha[i], &hb[i], &hc[i]); 100 for (int i = 2; i <= n; i++) { 101 gx.add(0,i-1,hc[i]*X); 102 int k; 103 scanf("%d", &k); 104 while (k--) { 105 int j; 106 scanf("%d", &j); 107 j++; 108 if (j != i) { 109 int c = dist(i, j); 110 gx.add(i-1,j-1,c); 111 } 112 } 113 } 114 int ans=gx.solve(0,n); 115 if (ans==-1) puts("Impossible"); 116 else printf("%d\n",ans); 117 } 118 return 0; 119 }
根为1,矩阵存的。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #define mt(a,b) memset(a,b,sizeof(a)) 5 using namespace std; 6 typedef __int64 LL; 7 const int inf=0x3f3f3f3f; 8 class Directed_MST_Matrix { ///最小树形图(有向图邻接阵)o(MV*ME) 9 typedef int typec;///边权的类型 10 static const int MV=1024;///点的个数 11 int s,l,r,n,id[MV],mark[MV],pre[MV],f[MV]; 12 bool vis[MV];///g[][]边权初始化为-1,结果ans为-1表示不存在 13 typec g[MV][MV],ans,mincost[MV]; 14 void dfs(int v) { 15 s++; 16 vis[v]=true; 17 for(int i=1; i<=n; i++) { 18 if(!vis[i]&&g[v][i]!=-1) 19 dfs(i); 20 } 21 } 22 void combine() { 23 mt(vis,0); 24 for(int i=l; i<=r; i++) 25 vis[f[i]]=true; 26 int now=f[l]; 27 for(int i=l; i<=r; i++) { 28 int x=f[i]; 29 ans+=mincost[x]; 30 id[x]=now; 31 for(int j=1; j<=n; j++) { 32 if(!vis[j]&&id[j]==j) { 33 if(g[j][x]!=-1) { 34 typec tmp=g[j][x]-mincost[x]; 35 if(g[j][now]==-1||tmp<g[j][now]) 36 g[j][now]=tmp; 37 } 38 if((g[x][j]!=-1&&g[x][j]<g[now][j])||g[now][j]==-1) 39 g[now][j]=g[x][j]; 40 } 41 } 42 } 43 for(int i=2; i<=n; i++) 44 if(id[i]==i) 45 pre[i]=id[pre[i]]; 46 mincost[now]=inf; 47 for(int i=1; i<=n; i++) { 48 if(id[i]==i&&i!=now&&g[i][now]!=-1&&g[i][now]<mincost[now]) { 49 mincost[now]=g[i][now]; 50 pre[now]=i; 51 } 52 } 53 } 54 bool find_circle() { 55 mt(vis,0); 56 for(int k=2; k<=n; k++) { 57 if(!vis[k]&&id[k]==k) { 58 mt(mark,0); 59 int i=k; 60 r=0; 61 while(i!=1&&!mark[i]&&!vis[i]) { 62 r++; 63 f[r]=i; 64 mark[i]=r; 65 vis[i]=true; 66 i=pre[i]; 67 } 68 if (mark[i]) { 69 l=mark[i]; 70 return true; 71 } 72 } 73 } 74 return false; 75 } 76 public: 77 void init(int tn) { ///传入点数,下标1开始,生成以1为根的有向树 78 n=tn; 79 for(int i=1; i<=n; i++) 80 for(int j=1; j<=n; j++) 81 g[i][j]=i==j?0:-1; 82 } 83 void add(int u,int v,typec w) { 84 if(g[u][v]==-1||g[u][v]>w) { 85 g[u][v]=w; 86 } 87 } 88 typec solve() { 89 mt(vis,0); 90 s=0; 91 dfs(1); 92 if (s<n) { 93 return -1; 94 } else { 95 id[1]=1; 96 for(int i=2; i<=n; i++) { 97 id[i]=i; 98 mincost[i]=inf; 99 for(int j=1; j<=n; j++) { 100 if(j!=i&&g[j][i]!=-1&&g[j][i]<mincost[i]) { 101 mincost[i]=g[j][i]; 102 pre[i]=j; 103 } 104 } 105 } 106 ans=0; 107 } 108 while (find_circle()) combine(); 109 for(int i=2; i<=n; i++) 110 if (id[i]==i) 111 ans+=mincost[i]; 112 return ans; 113 } 114 }gx; 115 const int M=1024; 116 int ha[M],hb[M],hc[M]; 117 int X,Y,Z; 118 int dist(int i, int j) { 119 int ret = abs(ha[i] - ha[j]) + abs(hb[i] - hb[j]) + abs(hc[i] - hc[j]); 120 ret *= Y; 121 if (hc[i] < hc[j]) ret += Z; 122 return ret; 123 } 124 int main() { 125 int n; 126 while(~scanf("%d%d%d%d",&n,&X,&Y,&Z),n+X+Y+Z) { 127 n++; 128 gx.init(n); 129 for (int i = 2; i <= n; i++) scanf("%d %d %d", &ha[i], &hb[i], &hc[i]); 130 for (int i = 2; i <= n; i++) { 131 gx.add(1,i,hc[i]*X); 132 int k; 133 scanf("%d", &k); 134 while (k--) { 135 int j; 136 scanf("%d", &j); 137 j++; 138 if (j != i) { 139 int c = dist(i, j); 140 gx.add(i,j,c); 141 } 142 } 143 } 144 int ans=gx.solve(); 145 if (ans==-1) puts("Impossible"); 146 else printf("%d\n",ans); 147 } 148 return 0; 149 }
Command Network http://poj.org/problem?id=3164
距离建图,权值是double,模板题。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #define mt(a,b) memset(a,b,sizeof(a)) 5 const int inf=0x3f3f3f3f; 6 const int M=128; 7 class Directed_MST { ///最小树形图(有向图) 8 typedef double typec;///边权的类型 9 static const int ME=M*M;///边的个数 10 static const int MV=M;///点的个数 11 struct E { 12 int u,v; 13 typec w; 14 } e[ME]; 15 int n,le,pre[MV],ID[MV],vis[MV]; 16 typec In[MV]; 17 public: 18 void init() { 19 le=0; 20 } 21 void add(int u,int v,typec w) { 22 e[le].u=u; 23 e[le].v=v; 24 e[le].w=w; 25 le++; 26 } 27 typec solve(int root,int tn) {///传入根和点的个数,点下标0开始 28 n=tn; 29 typec ret=0; 30 while(true) { 31 for(int i=0; i<n; i++) { 32 In[i]=inf; 33 } 34 for(int i=0; i<le; i++) { 35 int u=e[i].u; 36 int v=e[i].v; 37 if(e[i].w<In[v]&&u!=v) { 38 pre[v]=u; 39 In[v]=e[i].w; 40 } 41 } 42 for(int i=0; i<n; i++) { 43 if(i==root) continue; 44 if(In[i]==inf) return -1;///除了根以外有点没有入边,则根无法到达它 45 } 46 int cntnode=0;///找环 47 mt(ID,-1); 48 mt(vis,-1); 49 In[root]=0; 50 for(int i=0; i<n; i++) { ///标记每个环 51 ret+=In[i]; 52 int v=i; 53 while(vis[v]!=i&&ID[v]==-1&&v!=root) { 54 vis[v]=i; 55 v=pre[v]; 56 } 57 if(v!=root&&ID[v]==-1) { 58 for(int u=pre[v]; u!=v; u=pre[u]) { 59 ID[u]=cntnode; 60 } 61 ID[v]=cntnode++; 62 } 63 } 64 if(!cntnode) break;///无环 65 for(int i=0; i<n; i++) { 66 if(ID[i]==-1) { 67 ID[i]=cntnode++; 68 } 69 } 70 for(int i=0; i<le; i++) { ///缩点,重新标记 71 int v=e[i].v; 72 e[i].u=ID[e[i].u]; 73 e[i].v=ID[e[i].v]; 74 if(e[i].u!=e[i].v) { 75 e[i].w-=In[v]; 76 } 77 } 78 n=cntnode; 79 root=ID[root]; 80 } 81 return ret; 82 } 83 } gx; 84 struct point{ 85 double x,y; 86 }p[M]; 87 double Distance(point p1,point p2) { 88 return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)); 89 } 90 int main(){ 91 int n,m,u,v; 92 while(~scanf("%d%d",&n,&m)){ 93 for(int i=0;i<n;i++){ 94 scanf("%lf%lf",&p[i].x,&p[i].y); 95 } 96 gx.init(); 97 while(m--){ 98 scanf("%d%d",&u,&v); 99 u--; 100 v--; 101 gx.add(u,v,Distance(p[u],p[v])); 102 } 103 double ans=gx.solve(0,n); 104 if(ans==-1) puts("poor snoopy"); 105 else printf("%.2f\n",ans); 106 } 107 return 0; 108 }
用矩阵的模板来测测。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #define mt(a,b) memset(a,b,sizeof(a)) 5 const int inf=0x3f3f3f3f; 6 const int M=128; 7 class Directed_MST_Matrix { ///最小树形图(有向图邻接阵)o(MV*ME) 8 typedef double typec;///边权的类型 9 static const int MV=128;///点的个数 10 int s,l,r,n,id[MV],mark[MV],pre[MV],f[MV]; 11 bool vis[MV];///g[][]边权初始化为-1,结果ans为-1表示不存在 12 typec g[MV][MV],ans,mincost[MV]; 13 void dfs(int v) { 14 s++; 15 vis[v]=true; 16 for(int i=1; i<=n; i++) { 17 if(!vis[i]&&g[v][i]!=-1) 18 dfs(i); 19 } 20 } 21 void combine() { 22 mt(vis,0); 23 for(int i=l; i<=r; i++) 24 vis[f[i]]=true; 25 int now=f[l]; 26 for(int i=l; i<=r; i++) { 27 int x=f[i]; 28 ans+=mincost[x]; 29 id[x]=now; 30 for(int j=1; j<=n; j++) { 31 if(!vis[j]&&id[j]==j) { 32 if(g[j][x]!=-1) { 33 typec tmp=g[j][x]-mincost[x]; 34 if(g[j][now]==-1||tmp<g[j][now]) 35 g[j][now]=tmp; 36 } 37 if((g[x][j]!=-1&&g[x][j]<g[now][j])||g[now][j]==-1) 38 g[now][j]=g[x][j]; 39 } 40 } 41 } 42 for(int i=2; i<=n; i++) 43 if(id[i]==i) 44 pre[i]=id[pre[i]]; 45 mincost[now]=inf; 46 for(int i=1; i<=n; i++) { 47 if(id[i]==i&&i!=now&&g[i][now]!=-1&&g[i][now]<mincost[now]) { 48 mincost[now]=g[i][now]; 49 pre[now]=i; 50 } 51 } 52 } 53 bool find_circle() { 54 mt(vis,0); 55 for(int k=2; k<=n; k++) { 56 if(!vis[k]&&id[k]==k) { 57 mt(mark,0); 58 int i=k; 59 r=0; 60 while(i!=1&&!mark[i]&&!vis[i]) { 61 r++; 62 f[r]=i; 63 mark[i]=r; 64 vis[i]=true; 65 i=pre[i]; 66 } 67 if (mark[i]) { 68 l=mark[i]; 69 return true; 70 } 71 } 72 } 73 return false; 74 } 75 public: 76 void init(int tn) { ///传入点数,下标1开始,生成以1为根的有向树 77 n=tn; 78 for(int i=1; i<=n; i++) 79 for(int j=1; j<=n; j++) 80 g[i][j]=i==j?0:-1; 81 } 82 void add(int u,int v,typec w) { 83 if(g[u][v]==-1||g[u][v]>w) { 84 g[u][v]=w; 85 } 86 } 87 typec solve() { 88 mt(vis,0); 89 s=0; 90 dfs(1); 91 if (s<n) { 92 return -1; 93 } else { 94 id[1]=1; 95 for(int i=2; i<=n; i++) { 96 id[i]=i; 97 mincost[i]=inf; 98 for(int j=1; j<=n; j++) { 99 if(j!=i&&g[j][i]!=-1&&g[j][i]<mincost[i]) { 100 mincost[i]=g[j][i]; 101 pre[i]=j; 102 } 103 } 104 } 105 ans=0; 106 } 107 while (find_circle()) combine(); 108 for(int i=2; i<=n; i++) 109 if (id[i]==i) 110 ans+=mincost[i]; 111 return ans; 112 } 113 }gx; 114 struct point{ 115 double x,y; 116 }p[M]; 117 double Distance(point p1,point p2) { 118 return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)); 119 } 120 int main(){ 121 int n,m,u,v; 122 while(~scanf("%d%d",&n,&m)){ 123 for(int i=1;i<=n;i++){ 124 scanf("%lf%lf",&p[i].x,&p[i].y); 125 } 126 gx.init(n); 127 while(m--){ 128 scanf("%d%d",&u,&v); 129 gx.add(u,v,Distance(p[u],p[v])); 130 } 131 double ans=gx.solve(); 132 if(ans==-1) puts("poor snoopy"); 133 else printf("%.2f\n",ans); 134 } 135 return 0; 136 }
end