题意
分析:
最大权闭合子图
题解讲得非常清晰
然后,正权值是由原点连向该点,容量为该点权值。
负权值是由该点连向汇点,容量为该点的权值的相反数。
结果就是:所有正权值之和-最小割。
本题由于只有第一层权值为正,所以最优性可以保证合法性(即不会只选择后面某个子图)
建完图大概是这个样子:
然后就可以过了。
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define SF scanf
#define PF printf
#define MAXN 310
#define MAXM 20610
#define INF 0x3FFFFFFF
using namespace std;
char S[MAXN];
int n,s,t,A[10],B[10],id1[MAXN][MAXN],id2[MAXN],id3[10],tot;
int W[MAXN][MAXN];
vector<int> a[MAXM],rev[MAXM],w[MAXM];
void add_edge(int u,int v,int val){
a[u].push_back(v);
w[u].push_back(val);
a[v].push_back(u);
w[v].push_back(0);
rev[u].push_back(a[v].size()-1);
rev[v].push_back(a[u].size()-1);
}
int d[MAXM],g[MAXM];
int dfs(int f,int x){
if(x==t)
return f;
int les=f;
for(int i=0;i<int(a[x].size())&⩽i++){
int u=a[x][i];
if(d[u]==d[x]-1&&w[x][i]){
int res=dfs(min(f,w[x][i]),u);
w[x][i]-=res;
w[u][rev[x][i]]+=res;
les-=res;
if(d[s]>tot)
return f-les;
}
}
if(les==f){
g[d[x]]--;
if(g[d[x]]==0){
d[s]=tot+1;
return 0;
}
d[x]=tot;
for(int i=0;i<int(a[x].size());i++)
if(w[x][i])
d[x]=min(d[x],d[a[x][i]]);
d[x]++;
g[d[x]]++;
}
return f-les;
}
int maxflow(){
g[0]=tot;
int res=0;
while(d[s]<tot)
res+=dfs(INF,s);
return res;
}
void init(){
for(int i=0;i<tot;i++)
a[i].clear(),w[i].clear(),rev[i].clear();
memset(d,0,sizeof d);
memset(g,0,sizeof g);
}
int main(){
freopen("value.in","r",stdin);
freopen("value.out","w",stdout);
int T;
SF("%d",&T);
while(T--){
init();
SF("%d",&n);
SF("%s",S);
for(int i=0;i<=9;i++)
SF("%d%d",&A[i],&B[i]);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
SF("%d",&W[i][j]);
s=1,t=2;
tot=3;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
id1[i][j]=i*n+j+tot;
tot+=n*n;
for(int i=0;i<n;i++)
id2[i]=i+tot;
tot+=n;
for(int i=0;i<10;i++)
id3[i]=i+tot;
tot+=10;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
if(i==j)
continue;
add_edge(id1[i][j],id2[i],INF);
add_edge(id1[i][j],id2[j],INF);
}
for(int i=0;i<n;i++)
add_edge(id2[i],id3[S[i]-'0'],INF);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(i!=j)
add_edge(s,id1[i][j],W[i][j]);
for(int i=0;i<n;i++)
add_edge(id2[i],t,A[S[i]-'0']);
for(int i=0;i<10;i++){
if(A[i]-B[i]>0)
add_edge(s,id3[i],A[i]-B[i]);
else
add_edge(id3[i],t,B[i]-A[i]);
}
int ans=0;
for(int i=0;i<int(a[s].size());i++)
ans+=w[s][i];
ans-=maxflow();
PF("%d\n",ans);
}
}