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 }