URAL 1156 Two Rounds (DFS二分染色 + 分组背包)

#include <stdio.h>
#define MAX 110

int numOfTasks, numOfPairs;
int numOfProblems;
typedef struct Node{
	int to;
	int next;
}Node;
//用邻接链表存储题目
//注意数组别开小了,千万别只是开MAX的大小!!!
Node NodeArray[MAX * 2];
int numOfNodes;
int head[MAX];

int problemColor[MAX];

typedef struct Set{
	int stack[MAX];
	int top;
	int colorSize[3];
}Set;
Set SetArray[MAX];
int numOfSets;

int fail;
int mark[MAX][MAX];

void addPair(int from, int to){
	numOfNodes++;
	NodeArray[numOfNodes].to = to;
	NodeArray[numOfNodes].next = head[from];
	head[from] = numOfNodes;
}

void colorPairedProblems(int problem, int SetNum, int color){	
	problemColor[problem] = color;
	int top = ++(SetArray[SetNum].top);
	SetArray[SetNum].stack[top] = problem;
	SetArray[SetNum].colorSize[color]++;
	int pairColor = 3 - color;
	int i, pairedProblem, pairedProblemColor;
	for (i = head[problem]; i != 0; i = NodeArray[i].next){
		pairedProblem = NodeArray[i].to;
		pairedProblemColor = problemColor[pairedProblem];
		if (pairedProblemColor == color){
			fail = 1;
			return;
		}
		if (pairedProblemColor == 0)
			colorPairedProblems(pairedProblem, SetNum, pairColor);
		if (fail)
			return;
	}
}

int main(){
	//freopen("input1.txt", "r", stdin);

	scanf("%d%d", &numOfTasks, &numOfPairs);
	numOfProblems = numOfTasks << 1;
	int i, one, another;
	for (i = 1; i <= numOfPairs; i++){
		scanf("%d%d", &one, &another);
		addPair(one, another);
		addPair(another, one);
	}

	for (i = 1; i <= numOfProblems; i++){
		if (problemColor[i] == 0){
			numOfSets++;	
			colorPairedProblems(i, numOfSets, 1);
		}
		if (fail){
			printf("IMPOSSIBLE\n");
			return 0;
		}
	}

	mark[0][0] = 1;
	int set, tasks, tempTasks;
	for (set = 1; set <= numOfSets; set++)
		for (tasks = 0; tasks <= numOfTasks; tasks++){
			if (mark[set - 1][tasks] != 0){
				tempTasks = tasks + SetArray[set].colorSize[1];
				if (tempTasks <= numOfTasks && mark[set][tempTasks] == 0)
					mark[set][tempTasks] = 1;
				tempTasks = tasks + SetArray[set].colorSize[2];
				if (tempTasks <= numOfTasks && mark[set][tempTasks] == 0)
					mark[set][tempTasks] = 2;
			}
		}

	if (mark[numOfSets][numOfTasks] == 0){
		printf("IMPOSSIBLE\n");
		return 0;
	}

	int numOfTaskLeft = numOfTasks;
	int top, tempProblem, j;
	for (set = numOfSets; set > 0; set--){
		if (mark[set][numOfTaskLeft] == 2){
			top = SetArray[set].top;
			//把集合set的所有问题problem的颜色取反
			for (j = 1; j <= top; j++){
				tempProblem = SetArray[set].stack[j];
				problemColor[tempProblem] = 3 - problemColor[tempProblem];
			}
			numOfTaskLeft -= SetArray[set].colorSize[2];
		}
		else
			numOfTaskLeft -= SetArray[set].colorSize[1];
	}

	for (i = 1; i <= numOfProblems; i++)
		if (problemColor[i] == 1)
			printf("%d ", i);
	printf("\n");

	for (i = 1; i <= numOfProblems; i++)
		if (problemColor[i] == 2)
			printf("%d ", i);
	printf("\n");

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值