【网络流】BZOJ5228 省选十连测Bounce

分析:

网络流比较好的题
每个点拆成A和B两点
在这里插入图片描述
在这里插入图片描述
然后按照如图所示,每个点的A点向另一点的B点连边
最后如果那个点必须选,则不连从A到B的边(那条边表示这个点不加入最终方案)

#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#define SF scanf
#define PF printf
#define MAXN 100010
#define INF 0x3f3f3f3f
using namespace std;
vector<int> a[MAXN],w[MAXN],p[MAXN],rev[MAXN];
void add_edge(int u,int v,int len,int pri){
//    PF("[%d %d %d %d]\n",u,v,len,pri);
	a[u].push_back(v),a[v].push_back(u);
	w[u].push_back(len),w[v].push_back(0);
	p[u].push_back(pri),p[v].push_back(-pri);
	rev[u].push_back(a[v].size()-1),rev[v].push_back(a[u].size()-1);
}
int las[MAXN],lasid[MAXN];
int dist[MAXN];
int s,t;
bool inq[MAXN];
queue<int> q;
bool spfa(){
	memset(dist,0x3f3f3f3f,sizeof dist);
	q.push(s);
	dist[s]=0;
	while(!q.empty()){
		int x=q.front();
		q.pop();
		inq[x]=0;
		for(int i=0;i<int(a[x].size());i++){
			int u=a[x][i];
			if(w[x][i])
				if(dist[u]>dist[x]+p[x][i]){
					dist[u]=dist[x]+p[x][i];
					las[u]=x;
					lasid[u]=i;
					if(inq[u]==0){
                        q.push(u);
                        inq[u]=1;
					}
				}
		}
	}
//	PF("[%d]",dist[t]);
	return dist[t]<0x3f3f3f3f;
}
pair<int,int> maxf(){
	pair<int,int> res=make_pair(0,0);
	while(spfa()){
		int f=INF;
		for(int i=t;i!=s;i=las[i])
			f=min(w[las[i]][lasid[i]],f);
		for(int i=t;i!=s;i=las[i]){
			res.second+=f*p[las[i]][lasid[i]];
			w[las[i]][lasid[i]]-=f;
			w[i][rev[las[i]][lasid[i]]]+=f;
		}
		res.first+=f;
	}
//	PF("[%d %d]\n",res.first,res.second);
	return res;
}
int C,R,tot;
bool used[MAXN];
int main(){
	int T;
	SF("%d",&T);
	while(T--){
		int n,m;
		SF("%d%d",&n,&m);
		s=n*m*2;
		t=s+1;
		tot=t+1;
		for(int i=0;i<tot;i++)
			a[i].clear(),rev[i].clear(),w[i].clear(),p[i].clear();
		for(int i=0;i<n;i++)
			for(int j=0;j<m-1;j++){
				SF("%d",&C);
				if((i^j)&1)
					add_edge(i*m+j,i*m+j+1+n*m,1,-C);
				else
					add_edge(i*m+j+1,i*m+j+n*m,1,-C);
			}
		for(int i=0;i<n-1;i++)
			for(int j=0;j<m;j++){
				SF("%d",&R);
				if((i^j)&1)
					add_edge((i+1)*m+j,i*m+j+n*m,1,-R);
				else
					add_edge(i*m+j,(i+1)*m+j+n*m,1,-R);
			}
		int k,x,y;
		SF("%d",&k);
		memset(used,0,sizeof used);
		for(int i=0;i<k;i++){
			SF("%d%d",&x,&y);
			x--,y--;
			used[x*m+y]=1;
		}
		for(int i=0;i<n*m;i++){
			add_edge(s,i,1,0);
			add_edge(i+n*m,t,1,0);
			if(used[i]==0)
				add_edge(i,i+n*m,1,0);
		}
		pair<int,int> res=maxf();
		if(res.first!=n*m)
			PF("Impossible\n");
		else
			PF("%d\n",-res.second);
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值