Zoj 3646 Matrix Transformer 二分图完美匹配
2015-09-09 23:02
381 查看
题目大意:给你一个n * n 的二维图, 每个点都有一个方向, 上或者下, 用U和D表示, 蓝厚问你交换任意次整行后, 能不能让主对角线上全部都是U。
第一眼一看, 水题啊贪心搞一搞就行了啊,然后写到一半发现并不能随意水过去, 情况太多了Orz, 然后就想,难道是网络流,,当时一直以为有更简单的解法可是赶时间懒得想就直接dinic上去干了,,后来发现这题真是网络流, 每个U点的行和列对应点连边, 源点与横坐标连边, 汇点跟纵坐标连边, 然后跑一边最大流看流量是否能等于n就行。
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
#include <string>
#include <cctype>
#include <cstdio>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <sstream>
#include <iostream>
#include <algorithm>
using namespace std;
#define ls id<<1,l,mid
#define rs id<<1|1,mid+1,r
#define OFF(x) memset(x,-1,sizeof x)
#define CLR(x) memset(x,0,sizeof x)
#define MEM(x) memset(x,0x3f,sizeof x)
typedef long long ll ;
typedef pair<int,int> pii ;
const int maxm = 1e5+50 ;
const int maxn = 500 ;
const int inf = 0x3f3f3f3f ;
const int MOD = 1e9+7 ;
int pnt[maxm], nxt[maxm], cap[maxm];
int head[maxn], vis[maxn], cnt, ed,L[maxn], n;
char s[250][250];
int dfs(int u, int f) {
if (u == ed) return f;
int left = f;
for (int i = head[u]; ~i; i = nxt[i]) {
int v = pnt[i];
if (cap[i] <= 0 || L[v] != L[u] + 1) continue ;
int d = dfs(v, min(left, cap[i]));
if (d > 0) {
cap[i] -= d;
cap[i ^ 1] += d;
left -= d;
if (left == 0) break;
} else L[v] = 0;
}
return f - left;
}
bool bfs() {
CLR(L);
queue<int> q;
q.push(0);
L[0] = 1;
while (q.size()) {
int u = q.front();q.pop();
for (int i = head[u]; ~i; i = nxt[i]) {
int v = pnt[i];
if (L[v] || cap[i] <= 0) continue ;
L[v] = L[u] + 1;
q.push(v);
// printf("%d\n",v);
}
}
return L[ed];
}
int Max_Flow() {
int res = 0;
while (bfs()) {
// puts("**");
res += dfs(0, inf);
}
return res;
}
void add_edge(int u, int v, int w) {
pnt[cnt] = v;
nxt[cnt] = head[u];
cap[cnt] = w;
head[u] = cnt++;
}
void add_edges(int u, int v, int w) {
add_edge(u, v, w);
add_edge(v, u, 0);
}
int main () {
#ifdef LOCAL
freopen("C:\\Users\\Administrator\\Desktop\\in.txt","r",stdin);
// freopen("C:\\Users\\Administrator\\Desktop\\out.txt","w",stdout);
#endif
while (~scanf("%d", &n)) {
ed = n * 2 + 1;
OFF(head);cnt = 0;
for (int i = 1; i <= n; i++) scanf("%s", s[i] + 1);
for (int i = 1; i <= n; i++) {
add_edges(0, i, 1);
add_edges(n + i, ed, 1);
for (int j = 1; j <= n; j++) {
if (s[i][j] == 'U') add_edges(i, j + n, 1);
}
}
bool flag = Max_Flow() == n;
// cout << flag << "\n" ;
if (flag) puts("YES");
else puts("NO");
}
return 0;
}
第一眼一看, 水题啊贪心搞一搞就行了啊,然后写到一半发现并不能随意水过去, 情况太多了Orz, 然后就想,难道是网络流,,当时一直以为有更简单的解法可是赶时间懒得想就直接dinic上去干了,,后来发现这题真是网络流, 每个U点的行和列对应点连边, 源点与横坐标连边, 汇点跟纵坐标连边, 然后跑一边最大流看流量是否能等于n就行。
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
#include <string>
#include <cctype>
#include <cstdio>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <sstream>
#include <iostream>
#include <algorithm>
using namespace std;
#define ls id<<1,l,mid
#define rs id<<1|1,mid+1,r
#define OFF(x) memset(x,-1,sizeof x)
#define CLR(x) memset(x,0,sizeof x)
#define MEM(x) memset(x,0x3f,sizeof x)
typedef long long ll ;
typedef pair<int,int> pii ;
const int maxm = 1e5+50 ;
const int maxn = 500 ;
const int inf = 0x3f3f3f3f ;
const int MOD = 1e9+7 ;
int pnt[maxm], nxt[maxm], cap[maxm];
int head[maxn], vis[maxn], cnt, ed,L[maxn], n;
char s[250][250];
int dfs(int u, int f) {
if (u == ed) return f;
int left = f;
for (int i = head[u]; ~i; i = nxt[i]) {
int v = pnt[i];
if (cap[i] <= 0 || L[v] != L[u] + 1) continue ;
int d = dfs(v, min(left, cap[i]));
if (d > 0) {
cap[i] -= d;
cap[i ^ 1] += d;
left -= d;
if (left == 0) break;
} else L[v] = 0;
}
return f - left;
}
bool bfs() {
CLR(L);
queue<int> q;
q.push(0);
L[0] = 1;
while (q.size()) {
int u = q.front();q.pop();
for (int i = head[u]; ~i; i = nxt[i]) {
int v = pnt[i];
if (L[v] || cap[i] <= 0) continue ;
L[v] = L[u] + 1;
q.push(v);
// printf("%d\n",v);
}
}
return L[ed];
}
int Max_Flow() {
int res = 0;
while (bfs()) {
// puts("**");
res += dfs(0, inf);
}
return res;
}
void add_edge(int u, int v, int w) {
pnt[cnt] = v;
nxt[cnt] = head[u];
cap[cnt] = w;
head[u] = cnt++;
}
void add_edges(int u, int v, int w) {
add_edge(u, v, w);
add_edge(v, u, 0);
}
int main () {
#ifdef LOCAL
freopen("C:\\Users\\Administrator\\Desktop\\in.txt","r",stdin);
// freopen("C:\\Users\\Administrator\\Desktop\\out.txt","w",stdout);
#endif
while (~scanf("%d", &n)) {
ed = n * 2 + 1;
OFF(head);cnt = 0;
for (int i = 1; i <= n; i++) scanf("%s", s[i] + 1);
for (int i = 1; i <= n; i++) {
add_edges(0, i, 1);
add_edges(n + i, ed, 1);
for (int j = 1; j <= n; j++) {
if (s[i][j] == 'U') add_edges(i, j + n, 1);
}
}
bool flag = Max_Flow() == n;
// cout << flag << "\n" ;
if (flag) puts("YES");
else puts("NO");
}
return 0;
}
相关文章推荐
- java thread
- 每日编程训练20150909:typedef void (* unitest_func_t) (void);
- 设计模式:鸭子
- db2 常见命令
- C# 获取SHA256码
- 高精度模版
- HDU 1789 Doing Homework again
- 对称加密与非对称加密
- 使用ADB指令删除Android安装包
- android 获取当前activity的最顶层及添加布局
- [LeetCode]Course Schedule ||
- 零基础学python-13.5 多迭代器vs单迭代器
- 零基础学python-13.5 多迭代器vs单迭代器
- Uva 12549 Sentry Robots 网络流 - 二分图匹配
- 适配器模式
- java参数传递(值传递还是引用传递)
- 电子邮件的发展史
- Pranava Pra 使用教程
- Qt自定义事件实现及子线程向主线程传送事件消息(理论+代码)
- 01_电话拨号器