首页 > 代码库 > 星际转移问题(最大流 枚举)

星际转移问题(最大流 枚举)

使用并查集判断有无解,若有解枚举天数若最大流等于人数则可行。

 

//http://www.cnblogs.com/IMGavin/
#include <iostream>
#include <stdio.h>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <vector>
#include <map>
#include <stack>
#include <set>
#include <bitset>
#include <algorithm>
using namespace std;

typedef long long LL;
#define gets(A) fgets(A, 1e8, stdin)
const int INF = 0x3F3F3F3F, N = 10008, MOD = 1003, M = 1000000;

const double EPS = 1e-6;
int fa[N];

int Find(int x){
    while(x!=fa[x]){
        x=fa[x];
    }
    return x;
}
void Union(int x,int y){
    int fx=Find(x);
    int fy=Find(y);
    if(fx!=fy){
        fa[fy]=fx;
    }
}

int head[N], tot;
struct node{
	int u, v, cap, next;
}edge[M];
int cur[N], lev[N], s[N];

void init(){
	memset(head, -1, sizeof(head));
	tot = 0;
}

void add(int u, int v, int cap){
	edge[tot].u = u;
	edge[tot].v = v;
	edge[tot].cap = cap;
	edge[tot].next = head[u];
	head[u] = tot++;
//反向弧
	edge[tot].u = v;
	edge[tot].v = u;
	edge[tot].cap = 0;
	edge[tot].next = head[v];
	head[v] = tot++;
}

bool bfs(int st, int des){
	memset(lev, -1, sizeof(lev));
	lev[st] = 0;
	queue<int> q;
	q.push(st);
	while(!q.empty()){
		int u = q.front();
		q.pop();
		for(int i = head[u]; i != -1; i = edge[i].next){
			int v = edge[i].v;
			if(edge[i].cap && lev[v] == -1){
				lev[v] = lev[u] + 1;
				q.push(v);
				if(v == des){
					return true;
				}
			}
		}
	}
	return false;
}
//源点,汇点,点的数量
int dinic(int st, int des, int n){
	int ans = 0;
	while(bfs(st, des)){
		memcpy(cur, head, sizeof(int) * (n + 1));
		int u = st, top = 0;
		while(true){
			if(u == des){
				int mini = INF, loc;
				for(int i = 0; i < top; i++){
					if(mini > edge[s[i]].cap){
						mini = edge[s[i]].cap;
						loc = i;
					}
				}
				for(int i = 0; i < top; i++){
					edge[s[i]].cap -= mini;
					edge[s[i] ^ 1].cap += mini;
				}
				ans += mini;
				top = loc;
				u = edge[s[top]].u;
			}
			int &i = cur[u];//引用类型
			for(; i != -1; i = edge[i].next){
				int v = edge[i].v;
				if(edge[i].cap && lev[v] == lev[u] + 1){
					break;
				}
			}
			if(i != -1){
				s[top++] = i;
				u = edge[i].v;
			}else{
				if(!top){
					break;
				}
				lev[u] = -1;
				u = edge[s[--top]].u;
			}
		}
	}
	return ans;
}


std::vector<int> v[N];
int h[N];
int main(){
	int n, m, k;
	while(cin >> n >> m >> k){
		int st = 0;
		for(int i = 1; i <= n + 2; i++){
			fa[i] = i;
		}

		for(int i = 1; i <= m; i++){
			v[i].clear();
			cin>>h[i];
			int x;
			cin >> x;

			for(int j = 0; j < x; j++){
				int tp;
				cin >> tp;
				if(tp == 0){
					tp = n + 1;
				}else if(tp == -1){
					tp = n + 2;
				}
				v[i].push_back(tp);
				if(j){
					Union(v[i][j - 1], v[i][j]);
				}
			}
			if(h[i] == 0){
				i--;
				m--;
			}
		}
		if((m == 0 ) || (Find(n + 1) != Find(n + 2))){
			printf("0\n");
			continue;
		}

		for(int d = 1; ; d++){
			init();
			add(st, n + 1, k);

			for(int i = 1; i <= d; i++){
				for(int j = 1; j <= n + 2; j++){
					add((n + 2) * (i - 1) + j, (n + 2) * i + j, INF);
				}
				for(int j = 1; j <= m; j++){
					int a = v[j][(i - 1) % v[j].size()];
					int b = v[j][i % v[j].size()];
					a = (n + 2) * (i - 1) + a;
					b = (n + 2) * i + b;
					add(a, b, h[j]);
				}
			}
			int ans = dinic(st, (n + 2) * (d + 1), (n + 2) * (d + 1) + 1);
			
			if(ans == k){
				printf("%d\n", d);
				break;
			}
		}
	}

	return 0;
}

 

星际转移问题(最大流 枚举)