Online JudgeProblem SetAuthorsOnline ContestsUser
Web Board
Home Page
F.A.Qs
Statistical Charts
Problems
Submit Problem
Online Status
Prob.ID:
Register
Update your info
Authors ranklist
Current Contest
Past Contests
Scheduled Contests
Award Contest
User ID:
Password:
  Register

终于AC了,我来说一下我的建圖(布吉岛和大家的一不一样,懒得读代妈了qaq)

Posted by KatrineYang at 2016-07-16 18:15:43 on Problem 1149
我觉得关键是要想到用最大流啊!!!小弱之前没考虑这个啊看了讨论区才往这方面想0 0
建圖其实很自然的,首先可以建一个暴力巨无霸的圖(这个很trivial),就是每个猪圈ZJi根据被访问的时间顺序“分身”成很多个节点ZJik(被访问几次就分身几次),然后原点S和每个猪圈的第一个分身相连,猪圈ZJi的第k个分身和第k次访问这个猪圈的顾客GKj相连,然后GKj和ZJ(i)(k+1)相连。当然所有GKj和匯点T相连(除了和ST相关的边,数值都是无穷大)。

比如样例中,就有ZJ11,ZJ12,ZJ13,ZJ21,ZJ22,ZJ31,ZJ32和GK1,GK2,GK3。然后比如S和ZJ11,ZJ21,ZJ31相连,ZJ11通过GK1和ZJ12相连,等等。

但是这个圖的大小是O(mn),显然时间空间都会爆。
不过画出这个圖之后很容易发现很多顶点都是二度点,比如样例中GK1->ZJ12->GK2这条边,其中的ZJ12完全无此必要。再比如ZJ11,ZJ21这两条值分别为1和3的路,可以合并为值为4的路。由于所有ZJik的度数都是2(因为只有一个GKj是在第k次访问猪圈ZJi),对这个圖进行“缩水”,得到没有猪圈节点,只有S、T和GKj的圖。在这个圖中GKj连向GKk当且仅当存在一个猪圈,这两个顾客相继访问。所以对每个猪圈记录一个访问序列并把相邻位置的顾客对应节点连起来就行了,T端没有变化,S端的话,把首次访问不同猪圈的相同顾客的边合并。

比如样例中变为S,T,GK1,GK2,GK3五个点,S->GK1:4, S->GK2:10, GK1->GK2:wqd, GK1->GK3:wqd, GK1->T: 2, GK2->T: 3, GK3->T: 6, 其余为洞。之后就套用最大流就完了!
附代妈

#include <iostream>
#include <queue>
using namespace std;

int conn[1000][1000] = {0};
int N, M;

const int MAX = 2147483647/2;

int value = 0;

bool pushFlow(){
	queue<int> bfs;
	bfs.push(0);
	bool getT = false;
	bool state[103] = {false};
	int trace[103] = {0};
	while(!bfs.empty()){
		int idx = bfs.front();
		bfs.pop();
		for(int i = 1; i <= N+1; i++){
			if(conn[idx][i] <= 0 || state[i]) continue;
			trace[i] = idx;
			state[i] = true;
			if(i == N+1){
				getT = true;
				break;
			}
			bfs.push(i);
		}
		if(getT) break;
	}
	//for(int i = 0; i <= N+1; i++) cout << trace[i] << " "; cout << endl;
	if(!getT) return false;
	int minVal = MAX;
	int qian = trace[N+1], hou = N+1;
	while(1){
		if(conn[qian][hou] < minVal) minVal = conn[qian][hou];
		hou = qian;
		qian = trace[qian];
		if(hou == 0) break;
	}
	value += minVal;
	qian = trace[N+1], hou = N+1;
	while(1){
		if(conn[qian][hou] != MAX) conn[qian][hou] -= minVal;
		if(conn[hou][qian] != MAX && hou != N+1 && qian != 0) conn[hou][qian] += minVal;
		hou = qian;
		qian = trace[qian];
		if(hou == 0) break;
	}
	return true;
}

int main() {
	cin >> M >> N;
	int pigs[1003];
	for(int i = 1; i <= M; i++) cin >> pigs[i];
	int state[1003] = {0};
	int slian[103] = {0};
	for(int i = 1; i <= N; i++){
		int num;
		int cur = 0;
		cin >> num;
		for(int j = 1; j <= num; j++){
			int zj;
			cin >> zj;
			if(zj == cur) continue;
			cur = zj;
			if(state[zj] == 0){
				slian[i] += pigs[zj];
			}
			else{
				conn[state[zj]][i] = MAX;
			}
			state[zj] = i;
		}
		cin >> num;
		conn[i][N+1] = num;
	}
	for(int i = 1; i <= N; i++){
		conn[0][i] = slian[i];
	}
	/*
	for(int i = 0; i <= N+1; i++){
		for(int j = 0; j <= N+1; j++){
			cout << conn[i][j] << " ";
		}
		cout << endl;
	}
	*/
	while(pushFlow()){;}
	cout << value << endl;
	return 0;
}

Followed by:

Post your reply here:
User ID:
Password:
Title:

Content:

Home Page   Go Back  To top


All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator