(hdu step 6.3.1)Strategic Game(求用最少顶点数把全部边都覆盖,使用的是邻接表)

题目:

Strategic Game

Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 110 Accepted Submission(s): 75
 
Problem Description
Bob enjoys playing computer games, especially strategic games, but sometimes he cannot find the solution fast enough and then he is very sad. Now he has the following problem. He must defend a medieval city, the roads of which form a tree. He has to put the minimum number of soldiers on the nodes so that they can observe all the edges. Can you help him?

Your program should find the minimum number of soldiers that Bob has to put for a given tree.

The input file contains several data sets in text format. Each data set represents a tree with the following description:

the number of nodes
the description of each node in the following format
node_identifier:(number_of_roads) node_identifier1 node_identifier2 ... node_identifier
or
node_identifier:(0)

The node identifiers are integer numbers between 0 and n-1, for n nodes (0 < n <= 1500). Every edge appears only once in the input data.

For example for the tree: 

 

the solution is one soldier ( at the node 1).

The output should be printed on the standard output. For each given input data set, print one integer number in a single line that gives the result (the minimum number of soldiers). An example is given in the following table:
 
 
 
Sample Input
4
0:(1) 1
1:(2) 2 3
2:(0)
3:(0)
5
3:(3) 1 4 2
1:(1) 0
2:(0)
0:(0)
4:(0)
 
Sample Output
1
2
 
 
Source
Southeastern Europe 2000
 
Recommend
JGShining


题目分析:

               二分图,求最小顶点覆盖。简单题。这道题须要注意的是,用邻接矩阵来做会超时,数组开得太大,要用

邻接表来做。

最小顶点覆盖 = 最大匹配数/2


代码例如以下:

/*
 * a.cpp
 *
 *  Created on: 2015年3月13日
 *      Author: Administrator
 */

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>

using namespace std;

const int maxn = 1501;
//bool map[maxn][maxn];//这个是使用邻接矩阵实现时所须要用到的数据结构
vector<int> map[maxn];//这个是使用邻接表实现时所须要用到的数据结构.这时候map[i]里面村的就是愿意和结点i匹配的结点集合了
bool useif[maxn];//用于标记某个节点是否已经匹配
int link[maxn];//link[i] = t .表示结点i匹配的结点是t


int n;//节点数

/**
 * 用邻接表实现的,推断结点t能否找到匹配的节点
 */
bool can(int t){
	int i;

	int size = map[t].size();//获取元一个结点t匹配的结点的个数
	for(i = 0 ; i < size ; ++i){//遍历每个愿意和结点t匹配的结点
		int index = map[t][i];//获取愿意和节点t匹配的结点的序号
		if(useif[index] == false){//假设该节点还没有匹配
			useif[index] = true;//将该节点标记为已经匹配
			if(link[index] == - 1 || can(link[index])){//假设该节点还没有匹配的结点||该匹配结点能找到其它的匹配结点
				link[index] = t;//那么僵该节点的匹配结点设置为t

				return true;//返回true,表示可以t找到匹配的结点
			}
		}
	}

	return false;//返回false,表示结点t无法找到匹配的节点
}


/**
 * 求最大匹配数
 */
int max_match(){
	int num = 0;

	int i;
	for(i = 0 ; i < n ; ++i){//遍历全部节点,求最大匹配数
		memset(useif,false,sizeof(useif));
		if(can(i) == true){
			num++;
		}
	}

	return num;
}


int main(){
	while(scanf("%d",&n)!=EOF){
//		memset(map,false,sizeof(map));//使用邻接矩阵实现求最大匹配数时,清空map的写法
		int i;

		for(i = 0 ; i < n ; ++i){//使用邻接矩阵求最大匹配数时,清空map的写法
			map[i].clear();
		}
		memset(link,-1,sizeof(link));

		int a,b;
		for(i = 0 ; i < n ; ++i){
			scanf("%d:(%d)",&a,&b);

			int c;
			int j;
			for(j = 0 ; j < b ; ++j){
				scanf("%d",&c);
//				map[a][c] = true;//邻接矩阵建立关系的写法
//				map[c][a] = true;
				/**
				 * 这道题和Grils And Boys 的差别就在于
				 * 假设0 (2): 1 2  --->这个表示0与1和2相互认识
				 * 在Grils And Boys中,0会出如今1和2的描写叙述中如
				 * 1  (...): 0 ...
				 * 2  (...): 0 ...
				 *
				 * 可是这道题中0 (2): 1 2 表示的不过0认识1和2
				 * 但1和2不一定认识0.
				 * 在做的时候我们要把它转换成相互认识来做
				 */
				map[a].push_back(c);//邻接表建立关系的写法
				map[c].push_back(a);
			}
		}

		//最小顶点覆盖 = 最大匹配数/2
		printf("%d\n",max_match()/2);
	}

	return 0;
}







posted @ 2016-03-22 19:09  zfyouxi  阅读(205)  评论(0编辑  收藏  举报