【HDU5772】String Problem [网络流]

String Problem

Time Limit: 10 Sec  Memory Limit: 64 MB
[Submit][Status][Discuss]

Description

  

Input

  

Output

  

Sample Input

  1
  3
  135
  1 2
  1 2
  1 2
  1 2
  1 2
  1 2
  1 2
  1 2
  1 2
  1 2
  0 0 3
  1 0 0
  4 0 0

Sample Output

  3

HINT

  

Solution

  官方题解:

  首先将点分为3类

  第一类:Pij 表示第i个点和第j个点组合的点,那么Pij的权值等于w[i][j]+w[j][i](表示得到的价值

  第二类:原串中的n个点每个点拆出一个点,第i个点权值为 –a[s[i]] (表示需要的花费

  第三类:对于10种字符拆出10个点,每个点的权值为  -(b[x]-a[x])

  那么我们可以得到一个关系图 ,对于第一类中的点Pij,如果想要选择Pij,你就必须要选中第二类中的点i和j,对于第二类中的点如果你想选中第i个点,其对应的字符s[i],那么就必须选中第三类中s[i] 对应的点,因为每个种类的点第一次选中时花费是b[s[i]],而第二类中花费都是a[s[i]],一定要补上b[s[i]]-a[s[i]],而且只需要补上一次

  得到上面的关系图后然后就是普通的最大权闭合子图问题,直接求解即可。

  然后我们得到了若干关系,直接建边跑一边网络流即可。

Code

  1 #include<iostream>  
  2 #include<string>  
  3 #include<algorithm>  
  4 #include<cstdio>  
  5 #include<cstring>  
  6 #include<cstdlib>  
  7 #include<cmath>  
  8 #include<ctime>
  9 using namespace std;  
 10 
 11 const int ONE = 200005;
 12 const int POI = 6005;
 13 const int INF = 2147483640;
 14 
 15 int Q,n;
 16 int S,T;
 17 char s[105];
 18 int Val[105][105];
 19 int next[ONE],first[POI],go[ONE],w[ONE],tot;
 20 int Dep[POI],q[ONE],E[POI],tou,wei;
 21 int part1,part2,part3;
 22 int Ans;
 23 
 24 struct power
 25 {
 26         int a,b;
 27 }a[15];
 28 
 29 int get() 
 30 {
 31         int res=1,Q=1;  char c;
 32         while( (c=getchar())<48 || c>57)
 33         if(c=='-')Q=-1;
 34         if(Q) res=c-48; 
 35         while((c=getchar())>=48 && c<=57) 
 36         res=res*10+c-48; 
 37         return res*Q; 
 38 }
 39 
 40 void Add(int u,int v,int z)
 41 {
 42         next[++tot]=first[u];   first[u]=tot;   go[tot]=v;  w[tot]=z;
 43         next[++tot]=first[v];   first[v]=tot;   go[tot]=u;  w[tot]=0;
 44 }
 45     
 46 int Bfs()
 47 {
 48         memset(Dep,0,sizeof(Dep));
 49         tou=0;  wei=1;
 50         q[1]=S; Dep[S]=1;
 51         for(int i=S;i<=T;i++) E[i]=first[i];
 52         while(tou<wei)
 53         {
 54             int u=q[++tou];
 55             for(int e=first[u];e;e=next[e])
 56             {
 57                 int v=go[e];
 58                 if(Dep[v] || !w[e]) continue;
 59                 Dep[v]=Dep[u]+1;
 60                 q[++wei]=v;
 61             }
 62         }
 63         return (Dep[T]>0);
 64 }
 65  
 66 int Dfs(int u,int Limit)
 67 {
 68         if(u==T || !Limit) return Limit;
 69         int from=0,f;
 70         for(int &e=E[u];e;e=next[e])
 71         {
 72             int v=go[e];
 73             if(Dep[v]!=Dep[u]+1 || !w[e]) continue;
 74             f=Dfs(v,min(Limit,w[e]));
 75             w[e]-=f;
 76             w[((e-1)^1)+1]+=f;
 77             Limit-=f;
 78             from+=f;
 79             if(!Limit) break;
 80         }
 81         return from; 
 82 }
 83 
 84 void Solve()
 85 {
 86         Ans = tot = 0;
 87         memset(first,0,sizeof(first));
 88         n=get();
 89         scanf("%s",s+1);
 90         for(int i=0;i<10;i++)
 91             a[i].a=get(), a[i].b=get();
 92         for(int i=1;i<=n;i++)
 93         for(int j=1;j<=n;j++)
 94             Val[i][j]=get(); 
 95         
 96         part1 = n*(n-1)/2;    part2 = n;    part3 = 10;
 97         S=0;    T= part1 + part2 + part3 +1;
 98         int num = 0;
 99         for(int i=1;i<=n;i++)
100         for(int j=i+1;j<=n;j++)
101         {
102             num ++;    Ans += Val[i][j]+Val[j][i];
103             Add(S,num, Val[i][j]+Val[j][i]);
104             Add(num,part1+i, INF);
105             Add(num,part1+j, INF);
106         }
107 
108         for(int i=1;i<=n;i++)
109         {
110             Add(part1+i,T, a[s[i]-'0'].a);
111             Add(part1+i,part1+part2+s[i]-'0'+1, INF);
112         }
113 
114         for(int i=0;i<10;i++)
115             Add(part1+part2+i+1,T, a[i].b-a[i].a);
116 
117         while(Bfs()) Ans-=Dfs(S,INF);
118 
119         printf("%d
",Ans);
120 }
121 
122 int main()
123 {
124         Q=get();
125         while(Q--)
126             Solve();
127 }
View Code
原文地址:https://www.cnblogs.com/BearChild/p/6571177.html