UVA 1306 LA 2531 The K-League
2015-06-09 15:49
459 查看
题意:有n只队伍打比赛 给出每只队目前获胜和失败的场数 再给出两两队伍接下来的比赛场次 问你哪些队伍可能的冠军
思路:主要考察建图方法 我们要依次判断每只队伍是否可能获胜 对于队伍i 首先预处理出i获胜的总场数sum 对每两只队伍进行编号(比如(u, v)编号为x) 从源点连一条到该编号的边 容量为这两只队伍接下来要比的场次 然后从该编号向这两只队伍连边 容量INF 最后 对于每只队伍 分别向汇点连边 容量为为sum-win[u] 其中win[u]代表u这只队伍已经赢的场次 然后判断从源点连出的边是否都满流即可
思路:主要考察建图方法 我们要依次判断每只队伍是否可能获胜 对于队伍i 首先预处理出i获胜的总场数sum 对每两只队伍进行编号(比如(u, v)编号为x) 从源点连一条到该编号的边 容量为这两只队伍接下来要比的场次 然后从该编号向这两只队伍连边 容量INF 最后 对于每只队伍 分别向汇点连边 容量为为sum-win[u] 其中win[u]代表u这只队伍已经赢的场次 然后判断从源点连出的边是否都满流即可
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define REP( i, a, b ) for( int i = a; i < b; i++ ) #define FOR( i, a, b ) for( int i = a; i <= b; i++ ) #define CLR( a, x ) memset( a, x, sizeof a ) #define CPY( a, x ) memcpy( a, x, sizeof a ) const int maxn = 500 + 10; const int maxe = 250000 + 10; const int INF = 1e9; struct Edge{ int v, c, f; int next; Edge() {} Edge(int v, int c, int f, int next) : v(v), c(c), f(f), next(next) {} }; struct ISAP{ int n, s, t; int num[maxn], cur[maxn], d[maxn], p[maxn]; int Head[maxn], cntE; int Q[maxn], head, tail; Edge edge[maxe]; void Init(int n){ this -> n = n; cntE = 0; CLR(Head, -1); } void Add(int u, int v, int c){ edge[cntE] = Edge(v, c, 0, Head[u]); Head[u] = cntE++; edge[cntE] = Edge(u, 0, 0, Head[v]); Head[v] = cntE++; } void Bfs(){ CLR(d, -1); CLR(num, 0); d[t] = 0; head = tail = 0; Q[tail++] = t; num[0] = 1; while(head != tail){ int u = Q[head++]; for(int i = Head[u]; ~i; i = edge[i].next){ Edge &e = edge[i]; if(~d[e.v]) continue; d[e.v] = d[u] + 1; Q[tail++] = e.v; num[d[e.v]] ++; } } } int Maxflow(int s, int t){ this -> s = s; this -> t = t; CPY(cur, Head); Bfs(); int u = p[s] = s, flow = 0; while(d[s] < n){ if(u == t){ int f = INF, neck; for(int i = s; i != t; i = edge[cur[i]].v){ if(f > edge[cur[i]].c - edge[cur[i]].f){ f = edge[cur[i]].c - edge[cur[i]].f; neck = i; } } for(int i = s; i != t; i = edge[cur[i]].v){ edge[cur[i]].f += f; edge[cur[i]^1].f -= f; } flow += f; u = neck; } int ok = 0; for(int i = cur[u]; ~i; i = edge[i].next){ Edge &e = edge[i]; if(e.c > e.f && d[e.v] + 1 == d[u]){ ok = 1; cur[u] = i; p[e.v] = u; u = e.v; break; } } if(!ok){ int m = n - 1; if(--num[d[u]] == 0) break; for(int i = Head[u]; ~i; i = edge[i].next){ Edge &e = edge[i]; if(e.c - e.f > 0 && m > d[e.v]){ cur[u] = i; m = d[e.v]; } } ++num[d[u] = m + 1]; u = p[u]; } } return flow; } }solver; int n, win[maxn], match[maxn][maxn], S, T; void input(){ int x; scanf("%d", &n); FOR(i, 1, n) scanf("%d%d", &win[i], &x); FOR(i, 1, n) FOR(j, 1, n) scanf("%d", &match[i][j]); } bool build(int cur){ int sum = win[cur], flow = 0, cnt_match = n + 1, S = 0, T = n + n * (n - 1) / 2 + 1; FOR(i, 1, n) sum += match[cur][i]; solver.Init(T + 1); FOR(i, 1, n) FOR(j, i + 1, n){ if(sum < win[i] || sum < win[j]) return false; //这里要注意 如果某支队伍已经赢的场次大于cur这只队伍得冠军要赢的场次 那么直接返回false flow += match[i][j]; solver.Add(S, cnt_match, match[i][j]); solver.Add(cnt_match, i, INF); solver.Add(cnt_match, j, INF); cnt_match++; } FOR(i, 1, n) solver.Add(i, T, sum - win[i]); return flow == solver.Maxflow(S, T); } void solve(){ bool flag = false; FOR(i, 1, n) if(build(i)){ if(flag) printf(" "); printf("%d", i); flag = true; } printf("\n"); } int main() { //freopen("in.txt", "r", stdin); int T; scanf("%d", &T); while(T--){ input(); solve(); } return 0; }
相关文章推荐
- IBM云的商业动作之我见(1):IBM 收购 OpenStack 托管私有云公司 Blue Box [IBM Acquired Blue Box]
- Errors running builder 'Android Resource Manager' on Project java.lang.NullPointerException 解决方法
- UILabel 对文字设置多个颜色 画中线
- 导出带格式Excel插件msexcel-builder
- easyui datagrid 编辑器绑定事件
- Bluetooth---初步了解Android 蓝牙4.0
- 不使用UIImagePickerControllerOriginalImage获取相册图片
- 阿里Druid数据源的使用
- iOS 多线程开发之OperationQueue(一)概念+两种Operation
- 通过Android命令自动编译出build.xml文件
- 【转】理解 Android Build 系统----不错
- js 中return false;return true;return的区别
- CCirculaQueue
- Storyboard里面的几种Segue区别及视图的切换:push,modal,popover,replace和custom
- Leetcode题解(7)L51/N-Queens
- IOS中UUID存放在不同的地方
- 5.3.1 Unique Binary Sear Trees
- 动态计算UITableViewCell高度详解
- UILabel的属性总结
- Dictionary的TryGetValue方法