URAL 1736 Chinese Hockey 网络流+建图

题目链接:点击打开链接

题意:

给定n个队伍的得分情况,输出任意一个可行解。

n个队伍任意2个队伍 a, b 间有且仅有一场比赛。

比赛结果分4种:

1、a +3, b +0

2、a +0, b +3

3、a +2, b +1

4、a +1, b +2

我们发现其实每种结果2个队伍得分和总是3 且4种情况就是3的所有拆分和的形式。

所以我们把任意两个队伍组合成一个点。

把n个点连向源点,流上限为该队伍的得分。

对于1,2两个队伍

1 -> 点(1,2) 连流上限为3的边

2 -> 点(1,2) 连流上限为3的边

点(1,2) 到汇点连流上限为3的边。

若满流则有解。

1,2两个队伍间的情况就看点(1,2)的流入情况。


#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
typedef long long ll;
const int inf = (int)(1e9);
const int M = 200 + 2;
const int E = M * M * 6 + M * 3;
const int N = M * M + M + 5;
struct Edge {
	int from, to, cap, nex;
};

int head[N], egnum;
Edge eg[E];

int a[M], n, st, ed;
int id[M][M], rid[N], tot;
int win[M][M];

void add(int u, int v, int cap, int rw = 0) {
	Edge E = {u, v, cap, head[u]};
	eg[egnum] = E;
	head[u] = egnum++;
	
	Edge E2 = {v, u, rw, head[v]};
	eg[egnum] = E2;
	head[v] = egnum++;
}
int sign[N];
bool bfs(int from, int to) {
	memset(sign, -1, sizeof sign);
	sign[from] = 0;
	
	queue<int> q;
	q.push(from);
	while (!q.empty()) {
		int u = q.front();
		q.pop();
		for (int i = head[u]; i != -1; i = eg[i].nex) {
			int v = eg[i].to;
			if (sign[v] == -1 && eg[i].cap) {
				sign[v] = sign[u] + 1;
				q.push(v);
				if (sign[to] != -1)
					return true;
			}
		}
	}
	return false;
}
int Stack[N], top, cur[N];
int dicnic(int from, int to) {
	int ans = 0;
	while (bfs(from, to)) {
		memcpy(cur, head, sizeof head);
		int u = from;
		top = 0;
		while (true) {
			if (u == to) {
				int flow = inf, loc;
				for (int i = 0; i < top; ++i)
					if (flow > eg[Stack[i]].cap) {
						flow = eg[Stack[i]].cap;
						loc = i;
					}
				for (int i = 0; i < top; ++i) {
					eg[Stack[i]].cap -= flow;
					eg[Stack[i] ^ 1].cap += flow;
				}
				ans += flow;
				top = loc;
				u = eg[Stack[top]].from;
			}
			for (int i = cur[u]; i != -1; cur[u] = i = eg[i].nex)
				if (eg[i].cap && (sign[u] + 1 == sign[eg[i].to]))
					break;
			if (cur[u] != -1) {
				Stack[top++] = cur[u];
				u = eg[cur[u]].to;
			} else {
				if (top == 0)
					break;
				sign[u] = -1;
				u = eg[Stack[--top]].from;
			}
		}
	}
	return ans;
}
void init() {
	memset(head, -1, sizeof head);
	egnum = 0;
}
void pu(int x) {
	if (x == 0) {
		putchar('<');
	} else if (x == 1) {
		putchar('>');
	} else if (x == 2) {
		putchar('>');
		putchar('=');
	} else {
		putchar('<');
		putchar('=');
	}
}
void work() {
	int sum = 0, u, v;
	for (int i = 0; i < n; ++i) {
		scanf("%d", &a[i]);
		sum += a[i];
	}
	tot = n;
	for (int i = 0; i < n; ++i)
		for (int j = i + 1; j < n; ++j) {
			id[i][j] = ++tot;
			rid[tot] = j;
		}
	st = ++tot;
	ed = ++tot;
	init();
	for (int i = 0; i < n; ++i)
		add(st, i, a[i]);
	for (int i = 0; i < n; ++i)
		for (int j = i + 1; j < n; ++j) {
			add(i, id[i][j], 3);
			add(j, id[i][j], 3);
			add(id[i][j], ed, 3);
		}
	int g = dicnic(st, ed);
	if (g != sum) {
		puts("INCORRECT");
	} else {
		memset(win, -1, sizeof win);
		puts("CORRECT");
		for (int i = 0; i < egnum; ++i) {
			if (eg[i].from < n && eg[i].to > n && eg[i].to < st) {
				u = eg[i].from;
				v = rid[eg[i].to];
				if (u == v)
					continue;
				if (u > v)
					std::swap(u, v);
				if (win[u][v] == -1) {
					if (eg[i].cap == 0) {
						win[u][v] = 1; //1 = win, 0 = los, 2 = little win, 3 = little los
					} else if (eg[i].cap == 1) {
						win[u][v] = 2;
					} else if (eg[i].cap == 2) {
						win[u][v] = 3;
					} else {
						win[u][v] = 0;
					}
				}
			}
		}
		for (int i = 0; i < n; ++i)
			for (int j = i + 1; j < n; ++j) {
				printf("%d ", i + 1);
				pu(win[i][j]);
				printf(" %d\n", j + 1);
			}
	}
}
int main() {
	while (~scanf("%d", &n))
		work();
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值