Captain America,CF704D,有源汇上下界最小流

本文介绍了一种利用二分图匹配和网络流算法解决颜色调整问题的方法。通过将问题抽象为图论问题,文章详细阐述了如何构建图模型、设定边的容量,并运用Dinic算法求解最小流,最终输出最优方案。

正题

      首先我们假设全部选权值较小的颜色,将行列离散化,转化为二分图,对于一行或一列的限制来说,更改颜色数量的区间是一个范围,以此作为上下界与源汇连边,中间存在点(i,j)那么就从i向j连边,容量为1,最后看看可行的最小流是多少,就知道至少要改多少个成权值较大的颜色,才能满足方案.

      输出方案我们就把中间边的编号记下来,看看有没有流量即可,有流量说明改了.

      当前弧优化漏打一个&,T了半小时.

#include<bits/stdc++.h>
using namespace std;

const int N=200010,M=500010;
struct edge{
	int y,nex,c;
}s[M<<1];
struct node{
	int x,y,id;
}p[N];
int first[N],len=1,n,m,H,L,r,b,tp,s1,t1,s2,t2,op[N],sum[N][2],mmin[N][2];
int ans[N],head[N],d[N],qs[N],st,ed;
map<int,int> num[2];

bool cmp1(const node&a,const node&b){return a.x<b.x;}
bool cmp2(const node&a,const node&b){return a.y<b.y;}
void gmin(int&x,int d){x=min(x,d);}

void ins(int x,int y,int c){
	s[++len]=(edge){y,first[x],c};first[x]=len;
	s[++len]=(edge){x,first[y],0};first[y]=len;
}

bool bfs(int S,int T){
	for(int i=1;i<=t2;i++) first[i]=head[i],d[i]=0;
	d[qs[st=ed=1]=S]=1;
	while(st<=ed){
		int x=qs[st++];
		for(int i=first[x];i!=0;i=s[i].nex) if(s[i].c && !d[s[i].y]){
			d[s[i].y]=d[x]+1;
			qs[++ed]=s[i].y;
		}
	}
	return d[T]!=0;
}

int dfs(int x,int T,int t){
	if(x==T) return t;
	int tot=0;
	for(int&i=first[x];i!=0;i=s[i].nex) if(s[i].c && d[s[i].y]==d[x]+1){
		int now=dfs(s[i].y,T,min(t-tot,s[i].c));
		s[i].c-=now;s[i^1].c+=now;tot+=now;
		if(t==tot) break;
	}
	return tot;
}

int Dinic(int S,int T){
	int tot=0;
	while(bfs(S,T)){
		int dx=dfs(S,T,1e9);
		while(dx) tot+=dx,dx=dfs(S,T,1e9);
	}
	return tot;
}

int main(){
	scanf("%d %d",&n,&m);
	scanf("%d %d",&r,&b);
	if(r>b) swap(r,b),tp^=1;
	for(int i=1;i<=n;i++) scanf("%d %d",&p[i].x,&p[i].y),p[i].id=i;
	sort(p+1,p+1+n,cmp1);
	int las=0;
	for(int i=1;i<=n;i++) if(p[i].x==las) p[i].x=p[i-1].x;
		else las=p[i].x,p[i].x=p[i-1].x+1,num[0][las]=p[i].x;
	H=p[n].x;
	sort(p+1,p+1+n,cmp2);las=0;
	for(int i=1;i<=n;i++) if(p[i].y==las) p[i].y=p[i-1].y;
		else las=p[i].y,p[i].y=p[i-1].y+1,num[1][las]=p[i].y;
	L=p[n].y;
	s1=H+L+1;t1=s1+1;s2=t1+1;t2=s2+1;
	for(int i=1;i<=n;i++) 
		ins(p[i].x,H+p[i].y,1),ans[p[i].id]=len,sum[p[i].x][0]++,sum[p[i].y][1]++;
	for(int i=1;i<=H;i++) mmin[i][0]=sum[i][0];
	for(int i=1;i<=L;i++) mmin[i][1]=sum[i][1];
	int t,l,d;
	while(m--){
		scanf("%d %d %d",&t,&l,&d);t--;
		if(!num[t][l]) continue;
		gmin(mmin[num[t][l]][t],d);
	}
	for(int i=1;i<=H;i++) {
		int L=(sum[i][0]-mmin[i][0]+1)/2,R=sum[i][0]-L;
		if(L>R) {printf("-1");return 0;}
		op[s1]-=L;op[i]+=L;
		if(R-L) ins(s1,i,R-L);
	}
	for(int i=1;i<=L;i++) {
		int L=(sum[i][1]-mmin[i][1]+1)/2,R=sum[i][1]-L;
		if(L>R) {printf("-1");return 0;}
		op[H+i]-=L;op[t1]+=L;
		if(R-L) ins(H+i,t1,R-L);
	}
	int tot=0;
	for(int i=1;i<=t1;i++) 
		if(op[i]>0) ins(s2,i,op[i]),tot+=op[i];
		else if(op[i]<0) ins(i,t2,-op[i]);
	ins(t1,s1,1e9);
	for(int i=1;i<=t2;i++) head[i]=first[i];
	if(Dinic(s2,t2)!=tot) printf("-1\n");
	else{
		tot=s[len].c,s[len].c=s[len^1].c=0;
		tot-=Dinic(t1,s1);
		printf("%lld\n",1ll*tot*b+1ll*r*(n-tot));
		for(int i=1;i<=n;i++)
			printf(s[ans[i]].c^tp?"b":"r");
	}
}

 

源码地址: https://pan.quark.cn/s/d1f41682e390 miyoubiAuto 米游社每日米游币自动化Python脚本(务必使用Python3) 8更新:更换cookie的获取地址 注意:禁止在B站、贴吧、或各大论坛大肆传播! 作者已退游,项目不维护了。 如果有能力的可以pr修复。 小引一波 推荐关注几个非常可爱有趣的女孩! 欢迎B站搜索: @嘉然今天吃什么 @向晚大魔王 @乃琳Queen @贝拉kira 第三方库 食用方法 下载源码 在Global.py中设置米游社Cookie 运行myb.py 本地第一次运行时会自动生产一个文件储存cookie,请勿删除 当前仅支持单个账号! 获取Cookie方法 浏览器无痕模式打开 http://user.mihoyo.com/ ,登录账号 按,打开,找到并点击 按刷新页面,按下图复制 Cookie: How to get mys cookie 当触发时,可尝试按关闭,然后再次刷新页面,最后复制 Cookie。 也可以使用另一种方法: 复制代码 浏览器无痕模式打开 http://user.mihoyo.com/ ,登录账号 按,打开,找到并点击 控制台粘贴代码并运行,获得类似的输出信息 部分即为所需复制的 Cookie,点击确定复制 部署方法--腾讯云函数版(推荐! ) 下载项目源码和压缩包 进入项目文件夹打开命令行执行以下命令 xxxxxxx为通过上面方式或取得米游社cookie 一定要用双引号包裹!! 例如: png 复制返回内容(包括括号) 例如: QQ截图20210505031552.png 登录腾讯云函数官网 选择函数服务-新建-自定义创建 函数名称随意-地区随意-运行环境Python3....
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值