题目链接:点击打开链接

白书例题P369

注意的就是即使这队接下来全胜也是无法赢,要直接判掉。

#include<stdio.h>  
#include<string.h>  
#include<iostream>  
#include<math.h>  
#include<algorithm>  
#include<queue>  
#include<vector>  
using namespace std;  

#define ll int   

#define N 700  
#define M 20000  
#define inf 107374182  
#define inf64 1152921504606846976  
struct Edge{    
	ll from, to, cap, nex;    
}edge[M*2];//注意这个一定要够大 不然会re 还有反向弧    

ll head[N], edgenum;    
void add(ll u, ll v, ll cap, ll rw = 0){ //如果是有向边则:add(u,v,cap); 如果是无向边则:add(u,v,cap,cap);   
	Edge E = { u, v, cap, head[u]};    
	edge[ edgenum ] = E;    
	head[u] = edgenum ++;    

	Edge E2= { v, u, rw,  head[v]};    
	edge[ edgenum ] = E2;    
	head[v] = edgenum ++;    
}    
ll sign[N];    
bool BFS(ll from, ll to){    
	memset(sign, -1, sizeof(sign));    
	sign[from] = 0;    

	queue<ll>q;    
	q.push(from);    
	while( !q.empty() ){    
		ll u = q.front(); q.pop();    
		for(ll i = head[u]; i!=-1; i = edge[i].nex)    
		{    
			ll v = edge[i].to;    
			if(sign[v]==-1 && edge[i].cap)    
			{    
				sign[v] = sign[u] + 1, q.push(v);    
				if(sign[to] != -1)return true;    
			}    
		}    
	}    
	return false;    
}    
ll Stack[N], top, cur[N];    
ll Dinic(ll from, ll to){  
	ll ans = 0;    
	while( BFS(from, to) )    
	{    
		memcpy(cur, head, sizeof(head));    
		ll u = from;      top = 0;    
		while(1)    
		{    
			if(u == to)    
			{    
				ll flow = inf, loc;//loc 表示 Stack 中 cap 最小的边    
				for(ll i = 0; i < top; i++)    
					if(flow > edge[ Stack[i] ].cap)    
					{    
						flow = edge[Stack[i]].cap;    
						loc = i;    
					}    

					for(ll i = 0; i < top; i++)    
					{    
						edge[ Stack[i] ].cap -= flow;    
						edge[Stack[i]^1].cap += flow;    
					}    
					ans += flow;    
					top = loc;    
					u = edge[Stack[top]].from;    
			}    
			for(ll i = cur[u]; i!=-1; cur[u] = i = edge[i].nex)//cur[u] 表示u所在能增广的边的下标    
				if(edge[i].cap && (sign[u] + 1 == sign[ edge[i].to ]))break;    
			if(cur[u] != -1)    
			{    
				Stack[top++] = cur[u];    
				u = edge[ cur[u] ].to;    
			}    
			else    
			{    
				if( top == 0 )break;    
				sign[u] = -1;    
				u = edge[ Stack[--top] ].from;    
			}    
		}    
	}    
	return ans;    
}  
void init(){memset(head,-1,sizeof head);edgenum = 0;}  

int win[30], lose[30], lef[30][30], id[30][30], tot;
int n;
vector<int>ans;
bool ok(int x){	
	init();
	int from = 0, to = tot;
	int all = win[x];
	for(int i = 1; i <= n; i++)
		all += lef[i][x];
	int flow = 0;
	for(int i = 1; i <= n; i++)
		for(int j = i+1; j <= n; j++)
			if(lef[i][j])
			{
				add(from, id[i][j], lef[i][j]);
				add(id[i][j], i, inf);
				add(id[i][j], j, inf);
				flow += lef[i][j];
			}
	for(int i = 1; i <= n; i++) {
		if(win[i] > all)return false;
		else if(win[i] < all)
		add(i, to, all - win[i]);
	}

	return Dinic(from, to) == flow;
}
void solve(){
	for(int i = 1; i <= n; i++)
		if(ok(i))
			ans.push_back(i);
}
void input(){
	scanf("%d", &n);
	for(int i = 1; i <= n; i++)scanf("%d %d", &win[i], &lose[i]);
	tot = n+1;
	for(int i = 1; i <= n; i++)  
		for(int j = 1; j <= n; j++)
			scanf("%d", &lef[i][j]);
	tot = n+1;
	for(int i = 1; i <= n; i++)
		for(int j = i+1; j <= n; j++)
			id[i][j] = tot++;
}
int main(){
	int T;scanf("%d",&T);
	while(T--){
		input();
		ans.clear();
		solve();
		for(int i = 0; i < ans.size(); i++)
			printf("%d%c", ans[i], i==(int)ans.size()-1?'\n':' ');
	}
	return 0;
}