NEUQ-ACM Week10

P1525 [NOIP2010 提高组] 关押罪犯

思路:

1.怨气值从小到大单调可以二分答案查找最小值

2.判断两人两人构成的路径是否可以构成二分表,若可以则可以作为答案继续向更小的情况查找

3.判断是否可以构成二分表:bfs搜索使用染色法,首先把一个点标记成黑色(1),然后开始bfs,枚举所有与它相连的点,将它们标记成白色(2),不断遍历整张图,如果你发现下一个染色的点已经有了颜色,判断是否与此时你在的点颜色一致。若是颜色一致,说明染色存在冲突,无法拆成二分图

代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,sum,maxx,l,r,mid;
int a[100005],c[100005];
struct edge{
    int u;
	int w;
	int v;
}b[200005];
void add(int x,int y,int z){
	b[++sum].u=a[x];
	b[sum].v=y;
	b[sum].w=z;
	a[x]=sum;
}
bool bfs(int mid){
	memset(c,0,sizeof(c));
	queue<int>q;
	for(int i=1;i<=n;i++){
	    if(c[i]) continue;
        q.push(i);
		c[i]=1;
        while(!q.empty()){
            int k=q.front();
			q.pop();
	        for(int j=a[k];j;j=b[j].u){
	            if(b[j].w>=mid){   
	  	            if(c[b[j].v]==0){
		                c[b[j].v]=c[k]==1?2:1;
		                q.push(b[j].v);
	                }
		            else if(c[b[j].v]==c[k])
				        return false; 
	            }
	        }
        }
    }
    return true;
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int aa,bb,cc;
		cin>>aa>>bb>>cc;
		maxx=max(maxx,cc);
	    add(aa,bb,cc);
	    add(bb,aa,cc);
	}
	l=0;
	r=maxx+1;
	while(l+1<r){
		mid=(l+r)/2;
		if(bfs(mid)) r=mid;
		else l=mid;
	}
	cout<<l;
	return 0;
}

P3386 【模板】二分图最大匹配

思路:

1.以数组a标记数字所在集合,若两数在同一集合中则数组a中数字一致

2.分z为1和2两种情况判断(小心部分特殊情况)

代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,e;
int a[505][505],b[505];
bool f[505];
bool dfs(int u){
	for(int v=1;v<=m;v++){
		if(a[u][v]&&!f[v]){
			f[v]=true;
			if(b[v]==-1||dfs(b[v])){
				b[v]=u;
				return true;
			}
		}
	}
	return false;
}
int hungary(){
	int s=0;
	memset(b,-1,sizeof(b));
	for(int i=1;i<=n;i++){
		memset(f,false,sizeof(f));
		if(dfs(i)) s++;
	}
	return s;
}
int main(){
	cin>>n>>m>>e;
	for(int i=1;i<=e;i++){
		int u,v;
		cin>>u>>v;
		a[u][v]=1;
	}
	cout<<hungary();
	return 0;
}

P1129 [ZJOI2007] 矩阵游戏

思路:

1.构建二分图:一边为列数,一边为行数,若第i行第j列是1,就给列数j和行数i连一条路径

2.行和列匹配,但实际上则是路径和路径进行匹配,最后要行列相等的匹配,即最大匹配数等于边数的时候可以交换得到成功匹配,输出yes,否则输出no

代码:
#include<bits/stdc++.h>
using namespace std;
int T,n,s;
int a[505][505],m[505],f[505];
bool dfs(int x){
	for(int i=1;i<=n;i++){
		if(a[x][i]==1&&f[i]==0){
			f[i]=1;
			if(m[i]==0||dfs(m[i])){
				m[i]=x;
				return true;
			}
		}
	}
	return false;
}
int main(){
	cin>>T;
	for(int i=1;i<=T;i++){
		memset(a,0,sizeof(a));
		memset(m,0,sizeof(m));
		s=0;
		cin>>n;
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				cin>>a[i][j];
			}
		}
		for(int i=1;i<=n;i++){
			memset(f,0,sizeof(f));
			s+=dfs(i);
		}
		if(s==n) cout<<"Yes"<<endl;
		else cout<<"No"<<endl;
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值