[TJOI2015]线性规划

题目洛谷P3973、BZOJ3996。

题目大意:
给你n,参数b[][]和c[](里面的数均>0),要你求一个数组A[](0/1,1表示选择),已知:
1. 若同时选择X和Y,获得B[x][y]收益
2. 若选择了X,需要C[x]的代价
求最大的收益
解题思路:
我们将第一个条件转化为:若不同时选择X和Y,需要B[x][y]的代价。
然后,建最小割模。
将(i,j)看成一个点,从S向其连容量为B[i][j]+B[j][i](若i=j则只连B[i][j])。
将每个i看成一个点,向T连容量为C[i]的边。
然后因为选(i,j)必须要选i和j,所以从(i,j)分别向i和j连容量∞的边(i=j则只连一条)。
求出最小割,然后答案就是sum(B)-最小割。

C++ Code:

#include<bits/stdc++.h>
#define N 1005
#define INF 0x3f3f3f3f
int dis[N*N+N+5],iter[N*N+N+5],cnt=1,head[N*N+N+5],B[505][505],C[505],n,sm=0,level[N*N+N+5],q[7000005];
bool vis[N*N+N+5];
struct edge{
    int from,to,cap,nxt;
}e[(N*N+N+5)<<2];
inline int readint(){
    int c=getchar(),d=0;
    for(;!isdigit(c);c=getchar());
    for(;isdigit(c);c=getchar())
    d=(d<<3)+(d<<1)+(c^'0');
    return d;
}
inline void addedge(const int from,const int to,const int cap){
    e[++cnt]=(edge){from,to,cap,head[from]};
    head[from]=cnt;
    e[++cnt]=(edge){to,from,0,head[to]};
    head[to]=cnt;
}
void bfs(int s){
    memset(level,-1,sizeof(level));
    level[s]=0;
    int l=0,r=1;
    q[1]=s;
    while(l!=r){
        int u=q[l=l%7000000+1];
        for(int i=head[u];i!=-1;i=e[i].nxt){
            int v=e[i].to;
            if(level[v]<0&&e[i].cap>0){
                level[v]=level[u]+1;
                q[r=r%7000000+1]=v;
            }
        }
    }
}
int dfs(int u,int t,int f){
    if(u==t)return f;
    for(int& i=iter[u];i!=-1;i=e[i].nxt){
        int v=e[i].to;
        if(e[i].cap>0&&level[v]>level[u]){
            int d=dfs(v,t,std::min(f,e[i].cap));
            if(d){
                e[i].cap-=d;
                e[i^1].cap+=d;
                return d;
            }else level[v]=-1;
        }
    }
    return 0;
}
int max_flow(int s,int t){
    int flow=0;
    while(1){
        bfs(s);
        if(level[t]<0)return flow;
        memcpy(iter,head,sizeof(iter));
        int f;
        while(f=dfs(s,t,INF))flow+=f;
    }
}
int main(){
	n=readint();
	memset(head,-1,sizeof head);
	for(int i=1;i<=n;++i)
	for(int j=1;j<=n;++j)sm+=(B[i][j]=readint());
	for(int i=1;i<=n;++i)C[i]=readint();
	for(int i=1;i<=n;++i)
	for(int j=1;j<=n;++j){
		int flow=(i==j)?B[i][i]:B[i][j]+B[j][i];
		addedge(0,(i-1)*n+j,flow);
		addedge((i-1)*n+j,n*n+i,INF);
		if(i!=j)addedge((i-1)*n+j,n*n+j,INF);
	}
	for(int i=1;i<=n;++i)addedge(n*n+i,n*n+n+1,C[i]);
	printf("%d\n",sm-max_flow(0,n*n+n+1));
}

猜你喜欢

转载自www.cnblogs.com/Mrsrz/p/9105830.html