uva 10380 wa
Problem C
Shogi
Tournament
Input: standard input
Output: standard output
Time Limit: 25 seconds
Memory Limit: 32 MB
You are to compute, given a partially played Shogi tournament (Japanese chess), whether or not a particular player can still theoretically win the tournament and if so, the maximum number of points the player can be ahead of the player in second place. A tie is possible if two (or more) players get the same number of points; for this problem this is considered as a win with 0 points (no tiebreakers are used).
The tournament is a double round robin (everyone plays everyone else twice), and the only possible result in a game is either a win or a loss (draws very rarely occurs, and when they do, a new game is played to determine the winner). Any number of games may have been played so far in the tournament, and in any order.
Input
The input will contain several tournaments. The first line of the input contains an integer n (n ≤ 20) which is the number of tournament.
Each tournament description starts with a blank line followed by a line containing two integers m (2 ≤ m ≤ 50) and p (1 ≤ p ≤ m) describing the number of players in the tournament and for which player we want to determine if a win is possible.
Then follows m lines describing a cross table of the tournament, each line containing m entries. The entry on line y column x in the cross table contains the result in the two games played between player y and x. A '1' means that y won the game, '0' that y lost the game and '-' that the game has not yet been played. Of course, since a player doesn't play against himself, the elements in the diagonal are always '--'.
You may assume that the cross table is "complete" in the sense that if player y won his first game against player x, the opposite result can be found for player x in his first game against player y.
Output
If the player can't win the tournament, output only "Player p can't win!".
Otherwise output "Player p can with d point(s)." where d is the maximum amount of points ahead of second place player p can get. You should also assign results to all remaining games in the tournament so this is achieved, and print out a cross table with these results. The cross table should have the same format as the input, except that you should also print the final score for each player, see the sample output for the exact format. There should be a blank line before each cross table.
Separate each tournament in the output with a blank line.
Sample Input
3
2 2
-- -1
-0 --
4 1
-- -0 0- 0-
-1 -- 11 --
1- 00 -- -0
1- -- -1 --
3 2
-- -- --
-- -- --
-- -- --
Sample Output
Player 2 can win with 0 point(s).
-- 01 : 1
10 -- : 1
Player 1 can't win!
Player 2 can win with 3 point(s).
-- 00 10 : 1
11 -- 11 : 4
01 00 -- : 1
(Regionals 2002 Warm-up Contest, Problem setter: Jimmy Mårdell)
不知道是不是任意解都行。
1.先设p能赢得未进行的比赛。
2.建模:从源点加容量为还需比赛的场数c的弧到每个比赛点,比赛点指的是参与者相同的比赛;
然后连两条与容量为c的弧指向两个参与者,最后从每个参与者(除了询问者)连容量为二分值的弧指向汇点。这样二分容量,求最小值即可。
但WA了。
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<vector> #include<cstdlib> #include<algorithm> #include<queue> #include<map> using namespace std; #define LL long long #define ULL unsigned long long #define UINT unsigned int #define MAX_INT 0x7fffffff #define MAX_LL 0x7fffffffffffffff #define MAX(X,Y) ((X) > (Y) ? (X) : (Y)) #define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) #define INF 100000000 #define MAXN 1500 #define MAXM 8000 #define MAXT 55 #define cint const int struct edge{ int u, v, cap, flow, nxt; }e[MAXM]; int h[MAXN], cc; int cur[MAXN], d[MAXN]; void add(int u, int v, int cap){ e[cc]=(edge){u, v, cap, 0, h[u]}; h[u]=cc++; e[cc]=(edge){v, u, 0, 0, h[v]}; h[v]=cc++; } int vis[MAXN]; bool bfs(cint s, cint t){ queue<int> q; q.push(s); memset(vis, 0, sizeof(vis)); vis[s]=1; d[s]=0; while(!q.empty()){ int u=q.front(); q.pop(); for(int i=h[u]; i!=-1; i=e[i].nxt){ int v=e[i].v, cap=e[i].cap, ef=e[i].flow; if(!vis[v] && cap>ef){ vis[v]=1; d[v]=d[u]+1; q.push(v); } } } return vis[t]==1; } int dfs(int u, int a, cint &t){ if(u==t || !a) return a; int flow=0, f; for(int &i=cur[u]; i!=-1; i=e[i].nxt){ int v=e[i].v, cap=e[i].cap, ef=e[i].flow; if(d[v]==d[u]+1 && (f=dfs(v, MIN(cap-ef, a), t))>0){ flow+=f; e[i].flow+=f; e[i^1].flow-=f; a-=f; if(!a) break; } } return flow; } int tf[MAXT]; bool Dinic(cint &x, cint &tc, cint s, cint t, cint &sum, vector<int> &te){ int i; for(i=tc; i<cc; i+=2) e[i].cap=x; for(i=0; i<cc; i++) e[i].flow=0; int maxflow=0; while(bfs(s, t)){ for(i=0; i<t+1; i++) cur[i]=h[i]; maxflow+=dfs(s, INF, t); } if(maxflow==sum){ for(i=0; i<te.size(); i++){ int j=te[i]; tf[i] = e[j].flow; } } return maxflow==sum; } char w[MAXT][MAXT][2]; void print(cint player, cint m, cint n){ int i, j, cnt[MAXT], wp=0; for(i=player-1, j=0; j<m; j++) if(i!=j){ char &c1=w[i][j][0], &c2=w[i][j][1]; if(c1=='-') c1='1', w[j][i][0]='0'; if(c2=='-') c2='1', w[j][i][1]='0'; wp = wp + (c1=='1' ? 1 : 0) + (c2=='1' ? 1 : 0); } int cur=0, sec=0; for(i=0; i<m; i++){ for(j=i+1; j<m; j++){ char &c1=w[i][j][0], &c2=w[i][j][1], &rc1=w[j][i][0], &rc2=w[j][i][1]; if(c1=='-' || c2=='-'){ cint tflow=tf[cur++]; if(tflow==2) c1=c2='1', rc1=rc2='0'; else if(tflow==1){ if(c1=='-' && c2=='-') c1=rc2='1', c2=rc1='0'; else if(c1=='-') c1='1', rc1='0'; else c2='1', rc2='0'; } else{ if(c1=='-') c1='0', rc1='1'; if(c2=='-') c2='0', rc2='1'; } } } cnt[i]=0; for(j=0; j<m; j++){ if(w[i][j][0]=='1') cnt[i]++; if(w[i][j][1]=='1') cnt[i]++; } if(i!=player-1) sec=MAX(sec, cnt[i]); } if(wp<sec){ printf("Player %d can't win!\n", player); return; } printf("Player %d can win with %d point(s).\n\n", player, wp-sec); for(i=0; i<m; i++){ for(j=0; j<m; j++) printf("%c%c ", w[i][j][0], w[i][j][1]); printf(": %d\n", cnt[i]); } } int main(){ // freopen("C:\\Users\\Administrator\\Desktop\\in.txt","r",stdin); // freopen("C:\\Users\\Administrator\\Desktop\\out3.txt","w",stdout); int T; scanf(" %d", &T); for(int kase=0; kase<T; kase++){ int i, j, m, p; scanf(" %d %d", &m, &p); p--; memset(h, -1, sizeof(h)); cc=0; int cmp=1+m, sum=0; //sum--p不参加且还要比赛的场数 vector<int> te; for(i=0; i<m; i++) for(j=0; j<m; j++){ char &c1=w[i][j][0], &c2=w[i][j][1]; scanf(" %c %c", &c1, &c2); if(i==p || j==p || i>=j) continue; int cap=(c1=='-' ? 1 : 0) + (c2=='-' ? 1 : 0); if(cap){ add(0, cmp, cap); te.push_back(cc); add(cmp, i+1, cap); add(cmp, j+1, cap); cmp++; sum+=cap; } } int tc=cc; for(i=0; i<m; i++) if(i!=p) add(i+1, cmp, 0); int l=1, r=m<<1, mid, tmp=-1; while(l<=r){ mid=(l+r)>>1; if(Dinic(mid, tc, 0, cmp, sum, te)) tmp=mid, r=mid-1; else l=mid+1; } if(kase) printf("\n"); if(tmp==-1) printf("Player %d can't win!\n", p+1); else print(p+1, m, te.size()); } return 0; }
搜来的AC代码
#include <cstdio> #include <cstdlib> #include <cassert> #include <cmath> #include <iostream> #include <algorithm> #include <deque> #include <cstring> #include <vector> using namespace std; int N, P, gamesPlayed, gamesWon[64], gameV[64][64]; int seen[2000]; char table[64][64][2]; struct Edge { int x, y, cap; }; vector<Edge> E; vector<int> adj[2000], inadj[2000]; bool cmp(int i, int j) { return gamesWon[i] < gamesWon[j]; } void add(char s[2], char ch) { for (int i = 0; i < 2; i++) if (s[i] == '-') { s[i] = ch; return ;} } void addEdge(int x, int y) { Edge e1 = { x, y, 1}, e2 = { y, x, 0 }; adj[x].push_back(E.size()); inadj[y].push_back(E.size()); E.push_back(e1); adj[y].push_back(E.size()); inadj[x].push_back(E.size()); E.push_back(e2); } int dfs(int x) { if (x == 1) return 1; if (seen[x]++) return 0; for (int i = 0; i < (int)adj[x].size(); i++) { Edge &e = E[adj[x][i]]; if (e.cap > 0 && dfs(e.y)) { e.cap--; E[adj[x][i]^1].cap++; return 1; } } return 0; } int aug(int pl) { memset(seen, 0, sizeof(seen)); seen[0] = 1; if (!dfs(2+pl)) return 0; return 1; } int main() { // freopen("C:\\Users\\Administrator\\Desktop\\in.txt","r",stdin); // freopen("C:\\Users\\Administrator\\Desktop\\out4.txt","w",stdout); int T; scanf("%d", &T); for (int cs = 1; cs <= T; cs++) { if (cs > 1) printf("\n"); scanf("%d %d", &N, &P); P--; memset(gameV, 0xff, sizeof(gameV)); for (int i = 0, k = 3+N; i < N; i++) { for (int j = i+1; j < N; j++) { gameV[i][j] = gameV[j][i] = k; k++; } } gamesPlayed = 0; memset(gamesWon, 0, sizeof(gamesWon)); memset(table, 0xff, sizeof(table)); E.clear(); for (int i = 0; i < 2000; i++) { adj[i].clear(); inadj[i].clear(); } for (int y = 0; y < N; y++) { for (int x = 0; x < N; x++) { for (int i = 0; i < 2; i++) { char ch; scanf(" %c", &ch); table[y][x][i] = ch; if (x <= y) continue; if (ch == '-') { addEdge(gameV[y][x], 1); addEdge(2+x, gameV[y][x]); addEdge(2+y, gameV[y][x]); } else { gamesPlayed++; if (ch == '0') gamesWon[x]++; else gamesWon[y]++; } } } } while (aug(P)) { gamesWon[P]++; gamesPlayed++; } while (gamesPlayed < N*(N-1)) { int i, v[100]; for (i = 0; i < N; i++) v[i] = i; sort(v, v+N, cmp); for (i = 0; i < N; i++) { if (v[i] != P && aug(v[i])) break; } assert(i < N); gamesWon[v[i]]++; gamesPlayed++; } int m = 0; for (int x = 0; x < N; x++) if (x != P) m = max(m, gamesWon[x]); if (m > gamesWon[P]) { printf("Player %d can't win!\n", P+1); } else { printf("Player %d can win with %d point(s).\n\n", P+1, gamesWon[P] - m); for (int x = 0; x < N; x++) { for (int y = x+1; y < N; y++) { int v = gameV[x][y]; for (int i = 0; i < (int)inadj[v].size(); i++) { Edge &e = E[inadj[v][i]]; if (e.x == x+2 && e.cap == 0) { add(table[x][y], '1'); add(table[y][x], '0'); } if (e.x == y+2 && e.cap == 0) { add(table[y][x], '1'); add(table[x][y], '0'); } } } } for (int x = 0; x < N; x++) { for (int y = 0; y < N; y++) printf("%c%c ", table[x][y][0], table[x][y][1]); printf(": %d\n", gamesWon[x]); } } } }
过的几个样例:
4
2 2
-- -1
-0 --
4 1
-- -0 0- 0-
-1 -- 11 --
1- 00 -- -0
1- -- -1 --
3 2
-- -- --
-- -- --
-- -- --
6 4
-- -- -- -- -- --
-- -- -- -- -- --
-- -- -- -- -- --
-- -- -- -- -- --
-- -- -- -- -- --
-- -- -- -- -- --