题目链接:
String problem
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 65536/65536 K (Java/Others)
Problem Description
This is a simple problem about string. Now a string S contains only ‘0’-‘9’. ?? wants to select a subsequence from this string. And makes this subsequence score maximum. The subsequence’s score is calculated as follows:
Score= Value – Total_Cost
The calculation of the Cost is as follows:
If the number of characters x in the subsequence is kx, And the two coefficients are ax,bx,The cost of character x calculated as follows:
The calculation of the Value is as follows:
id[i] is the position of the subsequence’s ith character in the original string,for example,if the original string is “13579”,and the subsubquence is “159”,then the array id ={1,3,5}. The w is a weight matrix.
Score= Value – Total_Cost
The calculation of the Cost is as follows:
If the number of characters x in the subsequence is kx, And the two coefficients are ax,bx,The cost of character x calculated as follows:
{cost[x]=0,kx=0cost[x]=ax∗(kx−1)+bx,kx≠0
TotalCost=∑i=09cost[i]
The calculation of the Value is as follows:
Value=0;
for(int i=1;i<=length(substr);++i){
for(int j=1;j<=length(substr);++j){
if(i!=j)
Value+=w[id[i]][id[j]];
}
}
id[i] is the position of the subsequence’s ith character in the original string,for example,if the original string is “13579”,and the subsubquence is “159”,then the array id ={1,3,5}. The w is a weight matrix.
Input
The first line contains an integer T, denoting the number of the test cases.
For each test case, the first line contains one integers n, the length of a string.
Next line contains the string S.
Next ten lines,each line contains ai,bi,denote the char i’s(0-9) coefficients
Next is a n*n matrix w.
Limits:
T<=20,
0<=n<=100
0<=ai<=bi<=1000
0<=w[i][j]<=50
For each test case, the first line contains one integers n, the length of a string.
Next line contains the string S.
Next ten lines,each line contains ai,bi,denote the char i’s(0-9) coefficients
Next is a n*n matrix w.
Limits:
T<=20,
0<=n<=100
0<=ai<=bi<=1000
0<=w[i][j]<=50
Output
Each test output one line “Case #x: y” , where x is the case number ,staring from 1. y is the Maximum score.
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
Case #1: 3
题意:
求这个式子的最大值;
思路:
这个也是最大权闭合子图的应用,如果要选第i行第j个w[i][j]那么一定要选序列中第i个和第j个,选了第i个和第j个那么一定要选相应的数字了;
题解是这样给的:
第一类:Pij 表示第i个点和第j个点组合的点,那么Pij的权值等于w[i][j]+w[j][i](表示得分)
第二类:原串中的n个点每个点拆出一个点,第i个点权值为 –a[s[i]] (表示要花费)
第三类:对于10种字符拆出10个点,每个点的权值为 -(b[x]-a[x])
第二类:原串中的n个点每个点拆出一个点,第i个点权值为 –a[s[i]] (表示要花费)
第三类:对于10种字符拆出10个点,每个点的权值为 -(b[x]-a[x])
然后就是建图跑最大流的算法了;
AC代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <bits/stdc++.h> #include <stack> #include <map> using namespace std; #define For(i,j,n) for(int i=j;i<=n;i++) #define mst(ss,b) memset(ss,b,sizeof(ss)); typedef long long LL; template<class T> void read(T&num) { char CH; bool F=false; for(CH=getchar();CH<'0'||CH>'9';F= CH=='-',CH=getchar()); for(num=0;CH>='0'&&CH<='9';num=num*10+CH-'0',CH=getchar()); F && (num=-num); } int stk[70], tp; template<class T> inline void print(T p) { if(!p) { puts("0"); return; } while(p) stk[++ tp] = p%10, p/=10; while(tp) putchar(stk[tp--] + '0'); putchar(' '); } const LL mod=1e9+7; const double PI=acos(-1.0); const int inf=1e9; const int N=1e4+120; const int maxn=1e4+220; const double eps=1e-12; int a[12],b[12],c[110],w[110][110]; char str[110]; struct Edge { int from,to,cap,flow; }; vector<int>G[maxn]; vector<Edge>edges; int cur[maxn],d[maxn],s,t,n,m,sum; bool vis[maxn]; inline void add_edge(int from,int to,int cap) { edges.push_back((Edge){from,to,cap,0}); edges.push_back((Edge){to,from,0,0}); m=edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } bool bfs() { mst(vis,0); queue<int>qu; qu.push(s); d[s]=0;vis[s]=1; while(!qu.empty()) { int fr=qu.front();qu.pop(); for(int i=0;i<G[fr].size();i++) { Edge& e=edges[G[fr][i]]; if(!vis[e.to]&&e.cap>e.flow) { vis[e.to]=1; d[e.to]=d[fr]+1; qu.push(e.to); } } } return vis[t]; } int dfs(int x,int a) { if(x==t||a==0)return a; int flow=0,f; for(int& i=cur[x];i<G[x].size();i++) { Edge& e=edges[G[x][i]]; if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0) { e.flow+=f; edges[G[x][i]^1].flow-=f; flow+=f; a-=f; if(a==0)break; } } return flow; } int Dinic()//跑最大流Dinic算最小割 { int flow=0; while(bfs()) { mst(cur,0); flow+=dfs(s,inf); } return flow; } inline void Init()//建图 { sum=0;s=0; int tot=n+10; For(i,1,n) { For(j,i+1,n) { tot++; add_edge(tot,i,inf); add_edge(tot,j,inf); add_edge(s,tot,w[i][j]+w[j][i]); sum+=w[i][j]+w[j][i]; } } tot++;t=tot; For(i,1,n) { add_edge(i,c[i]+n+1,inf); add_edge(i,t,a[c[i]]); } For(i,0,9) { add_edge(i+n+1,t,b[i]-a[i]); } } int main() { int t,Case=0; read(t); while(t--) { edges.clear(); For(i,0,maxn-2)G[i].clear(); read(n); scanf("%s",str); For(i,0,n-1)c[i+1]=str[i]-'0'; For(i,0,9)read(a[i]),read(b[i]); For(i,1,n)For(j,1,n)read(w[i][j]); Init(); sum-=Dinic(); printf("Case #%d: %d ",++Case,sum); } return 0; }