2016 Multi-University Training Contest 4 T9

http://acm.hdu.edu.cn/showproblem.php?pid=5772

最大权闭合子图。

得到价值w[i][j]的条件是选了i,j这两个位置的字符。选择位置的i字符花费为

第一次选s[i]:a[s[i]]       不是第一次选s[i]:b[s[i]]

所以对于选i位置字符前提为选了花费为b[s[i]]-a[s[i]]的字符i。

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

 1 #include<cstdio>
 2 #include<cstring>
 3 #define M 120010
 4 #define N 6010
 5 #define inf 1000000000 
 6 int len[M <<1],e[M <<1],nex[M <<1],other[M <<1],head[N],last[N],d[N],num[N];
 7 int te,sum,_,j,num1,num2,w[110][110],a[11],b[11],m,n,i,ans,tot,ss,tt,ee,u,v,c;
 8 char s[110];
 9 int init()
10 {
11     memset(head,0,sizeof(head));
12     memset(num,0,sizeof(num));
13     memset(d,0,sizeof(d));
14     ans=ee=0;
15 }
16 int min(int a,int b)
17 {
18     return a<b?a:b;
19 }
20 void add(int u,int v,int c)
21 {
22     //printf("%d %d %d
",u,v,c);
23     other[++ee]=ee+1;
24     e[ee]=v;nex[ee]=head[u];head[u]=ee;len[ee]=c;
25     other[++ee]=ee-1;
26     e[ee]=u;nex[ee]=head[v];head[v]=ee;len[ee]=0;
27 }
28 int dfs(int x,int flow)
29 {
30     int rec,j,p;
31     if (x==tt) return flow;
32     rec=0;j=last[x];
33     while (j!=0)
34     {
35         if (len[j]>0 && d[x]==d[e[j]]+1)
36         {
37             last[x]=j;
38             p=dfs(e[j],min(len[j],flow-rec));
39             len[j]-=p;len[other[j]]+=p;
40             rec+=p;
41             if (rec==flow) return rec;
42         }
43     j=nex[j];
44     }
45     if (d[ss]>tot) return rec;
46      if (--num[d[x]]==0) d[ss]=tot;
47      last[x]=head[x];
48      num[++d[x]]++;
49      return rec;
50 }
51 int main()
52 {
53     scanf("%d",&_);
54     while (_--)
55     {
56         sum=0;init();
57         scanf("%d",&n);
58         scanf("%s",s+1);
59         for (i=0;i<=9;i++)
60             scanf("%d%d",&a[i],&b[i]);
61         for (i=1;i<=n;i++)
62             for (j=1;j<=n;j++)
63                 scanf("%d",&w[i][j]);
64         num1=1;ss=1;
65         for (i=1;i<=n;i++)
66             for (j=i+1;j<=n;j++)
67                 if (w[i][j]+w[j][i]!=0)
68                 {
69                     add(ss,++num1,w[i][j]+w[j][i]);
70                     sum+=w[i][j]+w[j][i];
71                 }
72         num2=1;tt=num1+n+11;
73         for (i=1;i<=n;i++)
74             for (j=i+1;j<=n;j++)
75                    if (w[i][j]+w[j][i]!=0)
76                   {
77                     add(++num2,num1+i,inf);
78                     add(num2,num1+j,inf);
79                 }
80         for (i=1;i<=n;i++)
81         {
82             add(num1+i,num1+n+s[i]-'0'+1,inf);
83             add(num1+i,tt,a[s[i]-'0']);
84         }
85         for (i=0;i<=9;i++)
86             add(num1+n+i+1,tt,b[i]-a[i]);
87         tot=num[0]=tt;
88         for (i=ss;i<=tt;i++)
89             last[i]=head[i];
90         while (d[ss]<tot)
91             ans+=dfs(ss,2147483647);
92         printf("Case #%d: %d
",++te,sum-ans);
93     }
94     return 0;
95     
96 }
View Code
Run ID Submit Time Judge Status Pro.ID Exe.Time Exe.Memory Code Len. Language Author
17819971 2016-07-29 15:40:45 Accepted 5772 15MS 2052K 2416 B G++ lbz007
------------------------------------------------------------------------- 花有重开日,人无再少年
原文地址:https://www.cnblogs.com/lbz007oi/p/5718783.html