kaungbing 匹配练习

HDU 1045 Fire Net
题面:给你一个不大于4*4的方格然后中间会有障碍格子,问其中能最多有多少个标记的方格,是无法直接(横竖方向上没有标记,或者被障碍挡住)达到的,看样例应该也能懂;

题解:每一个 行 对应一个 列 如果一行之中多了一个障碍物 分割了这一行那么当作新 行 来算 ,同理 列也是那么处理(这题爆搜也能过,不过和我预想练习的目的不一致就不在此解答了)

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
#include<set>
using namespace std;
const int maxn = 1e3+10;

namespace flow {
	struct edge {
		int to,cap,flow,rev;
		edge(int t,int c,int f,int r):to(t),cap(c),flow(f),rev(r){};
	};
	vector<edge>g[maxn+10];
	int S,T,ndcnt,d[maxn+10],cur[maxn+10];
	queue<int>q;

	void init(int ss,int tt,int nn) {
		S=ss;
		T=tt;
		for(int i=1; i<=ndcnt; i++)g[i].clear();
		ndcnt=nn;
	}
	void addedge(int l,int r,int w) {
		g[l].push_back(edge(r,w,0,(int)g[r].size()));
		g[r].push_back(edge(l,0,0,(int)g[l].size()-1));
	}
	bool bfs() {
		for(int i=1; i<=ndcnt; i++)
			d[i] = i == S ? 0 : -1;
		q.push(S);
		while(!q.empty()) {
			int p = q.front();
			q.pop();
			for(int i=0; i<g[p].size(); i++) {
				edge e = g[p][i];
				if(e.cap>e.flow && d[e.to] == -1) {
					d[e.to] = d[p] + 1;
					q.push(e.to);
				}
			}
		}
		return d[T] != -1;
	}
	int dfs(int p, int a) {
		if(p==T)return a;
		int ans=0,now;
		for(int &i = cur[p]; i<g[p].size(); i++) {
			edge &e = g[p][i];
			if(e.cap>e.flow && d[p]+1 == d[e.to]) {
				now = dfs(e.to,min(a,e.cap-e.flow));
				e.flow+=now;
				g[e.to][e.rev].flow-=now;
				ans+=now;
				a-=now;
				if(!a)break;
			}
		}
		return ans;
	}
	int solve() {
		int ans=0;
		while(bfs()) {
			for(int i=1; i<=ndcnt; i++) {
				cur[i]=0;
			}
			ans+=dfs(S,1e9);
		}
		return ans;
	}
}
char mp[100][100];
int p1[100][100],p2[100][100];
int main() {
	int n;
	while(scanf("%d",&n)) {
		if(n==0)break;
		for(int i=1; i<=n; i++) {
			scanf("%s",mp[i]+1);
		}
		flow:: init(99,100,105);
		int cnt=1;
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				p1[i][j]=cnt;
				if(mp[i][j]=='X')cnt++;
			}
			cnt++;
		}
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				p2[j][i]=cnt;
				if(mp[j][i]=='X')cnt++;
			}
			cnt++;
		}
		set<int>num1,num2;
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				if(mp[i][j]!='X'){
					flow::addedge(p1[i][j],p2[i][j],1);
					//cout<<p1[i][j]<<" "<<p2[i][j]<<endl;
				}
				num1.insert(p1[i][j]);
				num2.insert(p2[i][j]);
			}
		}
		for(int it:num1)flow::addedge(99,it,1);
		for(int it:num2)flow::addedge(it,100,1);
		
		printf("%d\n",flow::solve());
	}
	return 0;
}

HDU 2444

题面:挺绕,但是读懂后就比较简单,;
就是将一群人分成两个组,这两个组中没有相互认识的人,如果不能这么分则输出No,要不然就输出这两组的最大两两认识匹配.
思路:
先用:染色法(bfs,或者,dfs)标记,判断有误冲突;
然后分类完后进行建边,然后dinic跑一遍就好了

#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<vector>

using namespace std;
const int maxn = 10000;
namespace flow {

	struct edge {
		int to, cap, flow, rev;
		edge() {};
		edge(int a,int b,int c,int d):to(a),cap(b),flow(c),rev(d) {};
	};
	vector<edge> g[maxn + 10];
	int s, t, ndcnt, d[maxn + 10], cur[maxn + 10];
	queue<int> q;

	void init(int ss, int tt, int nn) {
		s = ss;
		t = tt;
		for (int i = 1; i <= ndcnt; ++i) g[i].clear();
		ndcnt = nn;
	}

	void addedge(int l, int r, int w) {
		g[l].push_back(edge(r, w, 0, (int)g[r].size()));
		g[r].push_back(edge(l, 0, 0, (int)g[l].size() - 1));
	}

	bool bfs() {
		for (int i = 1; i <= ndcnt; ++i)
			d[i] = i == s ? 0 : -1;
		q.push(s);
		while (!q.empty()) {
			int p = q.front();
			q.pop();
			for (int i = 0; i < (int)g[p].size(); ++i) {
				edge e = g[p][i];
				if (e.cap > e.flow && d[e.to] == -1) {
					d[e.to] = d[p] + 1;
					q.push(e.to);
				}
			}
		}
		return d[t] != -1;
	}

	int dfs(int p, int a) {
		if (p == t) return a;
		int ans = 0, now;
		for (int &i = cur[p]; i < (int)g[p].size(); ++i) {
			edge &e = g[p][i];
			if (e.cap > e.flow && d[p] + 1 == d[e.to]) {
				now = dfs(e.to, min(a, e.cap - e.flow));
				e.flow += now;
				g[e.to][e.rev].flow -= now;
				ans += now;
				a -= now;
				if (!a) break;
			}
		}
		return ans;
	}

	int solve() {
		int ans = 0;
		while (bfs()) {
			for (int i = 1; i <= ndcnt; ++i) cur[i] = 0;
			ans += dfs(s, 1e9);
		}
		return ans;
	}

}
int n,m;
vector<int>e[maxn];
int vis[maxn];

bool check() {
	for(int i=0; i<=n; i++)vis[i]=0;
	int flag=0;
	queue<int>q;
	for(int i=1; i<=n; i++) {
		q.push(i);
		if(vis[i]==0)vis[i]=1;
		while(!q.empty()) {
			int tmp = q.front(),ff = (vis[tmp]==1?2:1);
			q.pop();
			for(int it:e[tmp]) {
				if(vis[it]==0) {
					vis[it]=ff;
					q.push(it);
				} else {
					if(vis[tmp]==vis[it]) {
						flag=1;
						break;
					}
				}
				if(flag)break;
			}
			if(flag)break;
		}
	}
	return flag;
}
int main() {
	
	while(scanf("%d%d",&n,&m)!=EOF) {
		for(int i=0; i<=n; i++)
			e[i].clear();
		int ta,tb;
		for(int i=0; i<m; i++) {
			scanf("%d%d",&ta,&tb);
			e[ta].push_back(tb);
			e[tb].push_back(ta);
		}
		if(check()) {
			puts("No");
			continue;
		}
		flow::init(201,202,250);
		for(int i=0; i<=n; i++) {
			if(vis[i]!=1)continue;
			flow::addedge(201,i,1);
			for(int it:e[i])
				flow::addedge(i,it,1);
		}
		for(int i=0; i<=n; i++) {
			if(vis[i]==2)
				flow::addedge(i,202,1);
		}
		printf("%d\n",flow::solve());
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值