IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 【题解&比赛总结】gmoj6683 我图呢 -> 正文阅读

[数据结构与算法]【题解&比赛总结】gmoj6683 我图呢

题目大意

给你一个二分图,并告诉每个点的点权
要求二分图的最大独立集并使得权值最大,同时输出任意一组方案。

题解

是一道经典的二元关系最小割的问题。
我们要求二分图最大独立集,那么我们就可以考虑求最大匹配,即最大独立集=点数-最大匹配,具体证明为:

二分图的独立数等于顶点数减去最大匹配数,很显然的把最大匹配两端的点都从顶点集中去掉这个时候剩余的点是独立集,这是|V|-2*|M|,同时必然可以从每条匹配边的两端取一个点加入独立集并且保持其独立集性质。——百度百科

为了方便计算答案,我们可以考虑求最小点覆盖(等于最大匹配),这就是一个最小割的问题了。
我们先考虑有关答案的事情。
题目问的是在满足独立集最大的前提下使得点权和最大。
那么说我们可以给每个 w [ i ] w[i] w[i] 加上一个 i n f inf inf ,并且保证这个 i n f ≥ ∑ w [ i ] inf\ge \sum w[i] infw[i]
这是一个挺妙的做法,有什么好处呢?我们可以保证一种方案的 w w w 值无论多大,只要这种方案的点数没有另外的方案的点数多,这种方案的答案肯定会更小。
由此,我们可以开始建图了。
首先,我们先给这个二分图黑白染色(就是一个dfs的事情),假设左边的点为白色,右边的点为黑色。
那么我们新建一个源点和汇点,源点给每个白点连边,边权为 w w w ,每个黑点向汇点连边,边权同样为 w w w 。然后对于每个限制(即白点和黑点),我们连一条边权为 I N F ( I N F > i n f + w m a x ) INF(INF>inf+w_{max}) INF(INF>inf+wmax?) 的边。
然后我们去跑最小割。
a n s ′ = ∑ w [ i ] ans'=\sum w[i] ans=w[i] a n s = a n s ′ ? 最 大 流 ans=ans'-最大流 ans=ans?
我们考虑如何统计答案:
第二个答案是很好处理的,即 a n s ? m o d ? i n f ans\ mod \ inf ans?mod?inf (显然)
现在我们考虑第一个(跟第三个一样)答案怎么做:
我的方法是把 S S S 中左边的点+ T T T 中右边的点 S S S 中右边的点+ T T T 中左边的点的个数比较一下,然后输出。
但是题解中好像单输出了 S S S 中左边的点+ T T T 中右边的点,我也不是很明白,欢迎各位大佬来爆踩。

Code

#include<cstdio>
#include<queue>
#define ll long long
using namespace std;
const int N=605;
const ll inf=4e9;
const ll INF=inf*100000LL;
struct node{
	int to,next;
	ll f;
}e[2*N*N];
int n,m,cnt,s,t;
int head[N],dep[N],cur[N],x[N*N],y[N*N],pd[N];
bool bz[N],bj[N][N],vis;
ll w[N],ans;
void add(int u,int v,ll f){
	e[++cnt].to=v;
	e[cnt].f=f;
	e[cnt].next=head[u];
	head[u]=cnt;
	return;
}
void doit(int u,int c){
	pd[u]=c;
	if (c==0) add(s,u,w[u]),add(u,s,0);
	else add(u,t,w[u]),add(t,u,0);
	for (int i=1;i<=n;++i)
		if (u!=i&&pd[i]==-1&&bj[i][u])
			doit(i,c^1);
	return;
}
bool bfs(){
	for (int i=0;i<=t;++i) dep[i]=1<<30,bz[i]=0,cur[i]=head[i];
	queue<int>q;
	bz[s]=1;
	dep[s]=0;
	q.push(s);
	while (!q.empty()){
		int u=q.front();
		q.pop();
		bz[u]=0;
		for (int i=head[u];i;i=e[i].next){
			int v=e[i].to;
			if (dep[v]>dep[u]+1&&e[i].f){
				dep[v]=dep[u]+1;
				if (!bz[v]){
					bz[v]=1;
					q.push(v);
				}
			}
		}
	}
	return dep[t]!=(1<<30);
}
ll dfs(int u,ll flow){
	if (u==t){
		ans-=flow;
		return flow;
	}
	ll used=0;
	for (int i=cur[u];i;i=e[i].next){
		cur[u]=i;
		int v=e[i].to;
		if (dep[v]==dep[u]+1&&e[i].f){
			ll ff=dfs(v,min(flow,e[i].f));
			if (ff){
				used+=ff;
				e[i].f-=ff;
				e[i^1].f+=ff;
				if (used==ff) break;
			}
		}
	}
	return used;
}
void work(){
	while (bfs()){
		vis=1;
		while (vis) vis=0,dfs(s,INF-1);
	}
	return;
}
void find(int u){
	bz[u]=1;
	for (int i=head[u];i;i=e[i].next){
		int v=e[i].to;
		if (e[i].f&&!bz[v]) find(v);
	}
	return;
}
int main(){
	freopen("graph.in","r",stdin);
	freopen("graph.out","w",stdout);
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;++i) scanf("%lld",&w[i]),w[i]+=inf,ans+=w[i];
	cnt=1;
	for (int i=1;i<=m;++i){
		scanf("%d%d",&x[i],&y[i]);
		if (bj[x[i]][y[i]]) continue;
		bj[x[i]][y[i]]=bj[y[i]][x[i]]=1;
	}
	s=n+1;t=n+2;
	for (int i=1;i<=n;++i) pd[i]=-1;
	for (int i=1;i<=n;++i)
		if (pd[i]==-1) doit(i,0);
	for (int i=1;i<=m;++i){
		if (pd[x[i]]==1) x[i]^=y[i],y[i]^=x[i],x[i]^=y[i];
		add(x[i],y[i],INF);add(y[i],x[i],0);
	}
	work();
	for (int i=1;i<=t;++i) bz[i]=0;
	find(s);
	int ans1=0,ans2=0;
	for (int i=1;i<=n;++i) ans1+=(bz[i]^pd[i]);
	for (int i=1;i<=n;++i) ans2+=(bz[i]^pd[i])==0;
	printf("%d %lld\n",max(ans1,ans2),ans%inf);
	for (int i=1;i<=n;++i) printf("%d",ans1>=ans2?(bz[i]^pd[i]):((bz[i]^pd[i])==0));
	fclose(stdin);
	fclose(stdout);
	return 0;
}

(我也不知道我的代码为什么跑那么慢……)

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-07-15 16:28:07  更:2021-07-15 16:31:23 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/4 7:19:17-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码