最小树形图(有向图)

GGS-DDU http://acm.hdu.edu.cn/showproblem.php?pid=4966

建图待补,先做模板了。

  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 }
View Code

 

Transfer water http://acm.hdu.edu.cn/showproblem.php?pid=4009

待补,测模板。可以变根的,用邻接表存的。

  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 }
View Code

 根为1,矩阵存的。

  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 }
View Code

 

 

Command Network http://poj.org/problem?id=3164

距离建图,权值是double,模板题。

  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 }
View Code

 用矩阵的模板来测测。

  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 }
View Code

 

 

 

end

转载于:https://www.cnblogs.com/gaolzzxin/p/3945256.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值