日常刷专题日记:https://cn.vjudge.net/contest/292353

A

Courses

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 12234    Accepted Submission(s): 5715


 

Problem Description

Consider a group of N students and P courses. Each student visits zero, one or more than one courses. Your task is to determine whether it is possible to form a committee of exactly P students that satisfies simultaneously the conditions:

. every student in the committee represents a different course (a student can represent a course if he/she visits that course)

. each course has a representative in the committee

Your program should read sets of data from a text file. The first line of the input file contains the number of the data sets. Each data set is presented in the following format:

P N
Count1 Student1 1 Student1 2 ... Student1 Count1
Count2 Student2 1 Student2 2 ... Student2 Count2
...... 
CountP StudentP 1 StudentP 2 ... StudentP CountP

The first line in each data set contains two positive integers separated by one blank: P (1 <= P <= 100) - the number of courses and N (1 <= N <= 300) - the number of students. The next P lines describe in sequence of the courses . from course 1 to course P, each line describing a course. The description of course i is a line that starts with an integer Count i (0 <= Count i <= N) representing the number of students visiting course i. Next, after a blank, you'll find the Count i students, visiting the course, each two consecutive separated by one blank. Students are numbered with the positive integers from 1 to N.

There are no blank lines between consecutive sets of data. Input data are correct.

The result of the program is on the standard output. For each input data set the program prints on a single line "YES" if it is possible to form a committee and "NO" otherwise. There should not be any leading blanks at the start of the line.

An example of program input and output:

Sample Input

2

3 3

3 1 2

3 2 1 2

1 1

3 3

2 1 3

2 1 3

1 1

 

Sample Output

 

YES

NO

 

题意:p个课程n个学生。每个课程要选一个课代表,必须是选了这门课程的学生才能当课代表。

问是否每个课程都有一个课代表,一个学生只能当一个课代表。

输入解释:

第一行是测试数量t

第二行p,n

接下来p行,每i行代表第i个课程

每一行第一个数字num代表有num个学生学这门课程,接下来num个数字,代表每个学生的编号。

 

解法:裸的二分图的最大匹配,我用的匈牙利算法,每个课程和学生之间建一条联系(有向图和无向图都可以解释,反正用不着学生指向课程的那条有向边)套用最大匹配的算法即可

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1083

AC代码:

 

#include<Bits/stdc++.h>
using namespace std;
bool vis[110][310];
bool used[310];
int part[310];//三个数组最为标记 
int p,n,t;
bool find(int x)
{
	for(int i=1;i<=n;i++)//遍历学生,是否有学生与之匹配 
	{
		if(vis[x][i]&&!used[i])// used有什么用 
		{
			used[i]=1;
			if(!part[i]||find(part[i]))//可以转移的 
			{
				part[i]=x;
				return 1;
			}
		}
	}
	return 0;
}
int slove()//匹配函数 
{
	int ans=0;
	for(int i=1;i<=p;i++)//每个课程遍历,去干什么,
	//能不能被匹配,每一轮里面学生有没有被匹配到 
	{
		memset(used,0,sizeof(used));//某个课程的访问里,学生有没有被匹配 
		if(find(i)) ans++;//寻找有没有匹配的学生 
	}
	return ans;
}
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		memset(part,0,sizeof(part));
		memset(vis,0,sizeof(vis));
		scanf("%d%d",&p,&n);
		for(int i=1;i<=p;i++)
		{
			int num;
			scanf("%d",&num);
			for(int j=1;j<=num;j++)
			{
				int x;
				scanf("%d",&x);
				vis[i][x]=1;//处理关系 
			}
		}
		int ans=slove();
		if(ans==p)  printf("YES\n");
		else printf("NO\n");
	}
}

B

Card Game Cheater

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 2715    Accepted Submission(s): 1445

Problem Description

Adam and Eve play a card game using a regular deck of 52 cards. The rules are simple. The players sit on opposite sides of a table, facing each other. Each player gets k cards from the deck and, after looking at them, places the cards face down in a row on the table. Adam’s cards are numbered from 1 to k from his left, and Eve’s cards are numbered 1 to k from her right (so Eve’s i:th card is opposite Adam’s i:th card). The cards are turned face up, and points are awarded as follows (for each i ∈ {1, . . . , k}):
If Adam’s i:th card beats Eve’s i:th card, then Adam gets one point.
If Eve’s i:th card beats Adam’s i:th card, then Eve gets one point.
A card with higher value always beats a card with a lower value: a three beats a two, a four beats a three and a two, etc. An ace beats every card except (possibly) another ace.
If the two i:th cards have the same value, then the suit determines who wins: hearts beats all other suits, spades beats all suits except hearts, diamond beats only clubs, and clubs does not beat any suit. 
For example, the ten of spades beats the ten of diamonds but not the Jack of clubs. 
This ought to be a game of chance, but lately Eve is winning most of the time, and the reason is that she has started to use marked cards. In other words, she knows which cards Adam has on the table before he turns them face up. Using this information she orders her own cards so that she gets as many points as possible.
Your task is to, given Adam’s and Eve’s cards, determine how many points Eve will get if she plays optimally. 

Input

There will be several test cases. The first line of input will contain a single positive integer N giving the number of test cases. After that line follow the test cases.

Each test case starts with a line with a single positive integer k <= 26 which is the number of cards each player gets. The next line describes the k cards Adam has placed on the table, left to right. The next line describes the k cards Eve has (but she has not yet placed them on the table). A card is described by two characters, the first one being its value (2, 3, 4, 5, 6, 7, 8 ,9, T, J, Q, K, or A), and the second one being its suit (C, D, S, or H). Cards are separated by white spaces. So if Adam’s cards are the ten of clubs, the two of hearts, and the Jack of diamonds, that could be described by the line

TC 2H JD

Output

For each test case output a single line with the number of points Eve gets if she picks the optimal way to arrange her cards on the table.

Sample Input

3

1

JD

JH

2

5D TC

4C 5H

3

2H 3H 4H

2D 3D 4D

Sample Output

1

1

2

题意:有两个人Adam和,Eve,每人各有k张扑克牌。比较大小,问如何分配卡片使得Eve赢最多的分,类似田忌赛马。

第一行是Adam的,第二行是Eve的卡片。

先按照数字大小比较2,3,4,5,6,7,8,9,T,J,Q,K,A依次增大,若数字相同比较花色。

红桃Hearts>黑桃Spades>方块Diamonds>梅花Clubs

解法:

这种题居然放在二分图的专题里面?想不通

花色按照优先级4,3,2,1加上数字按照数值*10就成功的将牌转换为数字形式。

遍历Adam的卡片,在Eve的卡片里二分找是否有比此张卡片的的扑克牌,you,ans++且将此卡片从Eve持有的卡片里删掉

#include<Bits/stdc++.h>
using namespace std;
int p,n,t,k;
char s1[30][5],s2[30][5];
int getid(char x)
{
	if(x=='T') return 10;
	if(x=='J') return 11;
	if(x=='Q') return 12;
	if(x=='K') return 13;
	if(x=='A') return 14;
	return x-'0';
}
int get(char x){
	if(x=='H') return 4;
	if(x=='S') return 3;
	if(x=='D') return 2;
	return 1;
}
int main()
{
	cin>>t;
	while(t--)
	{
		scanf("%d",&k);
		for(int i=1;i<=k;i++) scanf("%s",s1[i]+1);
		for(int i=1;i<=k;i++) scanf("%s",s2[i]+1);
		vector<int>a;
		multiset<int>b;
		for(int i=1;i<=k;i++)
		{
			int ans=getid(s1[i][1])*10+get(s1[i][2]);
			a.push_back(ans);
		//	printf("ans:%d\n",ans);
		}
		for(int i=1;i<=k;i++)
		{
			int ans=getid(s2[i][1])*10+get(s2[i][2]);
			b.insert(ans);
		//	printf("ans:%d\n",ans);
		}
		sort(a.begin(),a.end());
		int ans=0;
		for(int i=0;i<a.size();i++)
		{
			int v=a[i];
			multiset<int>:: iterator it=b.lower_bound(v);
			if(it==b.end()) continue;
			if(*it>v) 
			{
				ans++;
				b.erase(it);
			}
		}
		printf("%d\n",ans);
	}
}

C:

Oil Skimming

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4227    Accepted Submission(s): 1734

Problem Description

Thanks to a certain "green" resources company, there is a new profitable industry of oil skimming. There are large slicks of crude oil floating in the Gulf of Mexico just waiting to be scooped up by enterprising oil barons. One such oil baron has a special plane that can skim the surface of the water collecting oil on the water's surface. However, each scoop covers a 10m by 20m rectangle (going either east/west or north/south). It also requires that the rectangle be completely covered in oil, otherwise the product is contaminated by pure ocean water and thus unprofitable! Given a map of an oil slick, the oil baron would like you to compute the maximum number of scoops that may be extracted. The map is an NxN grid where each cell represents a 10m square of water, and each cell is marked as either being covered in oil or pure water.

Input

The input starts with an integer K (1 <= K <= 100) indicating the number of cases. Each case starts with an integer N (1 <= N <= 600) indicating the size of the square grid. Each of the following N lines contains N characters that represent the cells of a row in the grid. A character of '#' represents an oily cell, and a character of '.' represents a pure water cell.

Output

For each case, one line should be produced, formatted exactly as follows: "Case X: M" where X is the case number (starting from 1) and M is the maximum number of scoops of oil that may be extracted.

Sample Input

1

6

......

.##...

.##...

....#.

....##

......

Sample Output

Case 1: 3

 题意:#代表着油区,. 代表海区。现有一个老板打算捞油赚大钱,现有的工具一次只能捞1*2的方块。不能捞着海区,因为油会不纯。

问最大能捞几次?

解法:把每一个油区和它周围的油区连一条无向边,然后就是二分图的裸题了。

这里的二分图最大匹配和第一个题有不太一样的地方,第一题课程和学生的编号是会有重复的。

建有向图slove里面第一层for循环只遍历课程。

这里建无向图slove里面第一层for循环需要遍历所有油区,因为油区的编号是唯一的。(一定是二分图,可以衍生如果有的题需要判断是否是二分图,那么可以再套一个染色判断二分图)

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int N=650;
char maps[N][N];
int cnt,fa[N*N],vis[N*N],sum[N][N];
int dir[4][2]={1,0,0,1,-1,0,0,-1};
vector<int>G[N*N];
bool find(int x)
{
	//printf("x:%d\n",x);
	for(int i=0;i<G[x].size();i++)
	{
		int y=G[x][i];
		if(!vis[y])
		{
			vis[y]=1;
			if(!fa[y]||find(fa[y]))
			{
				fa[y]=x;
				return 1;
			}
		}
	}
	return 0;
}
int slove()
{
	int ans=0;
	for(int i=1;i<=cnt;i++)
	{
		memset(vis,0,sizeof(vis));
		if(find(i)) ans++;
	}
	return ans;
}
void init()
{
	for(int i=0;i<=cnt;i++) G[i].clear();
	memset(fa,0,sizeof(fa));
	memset(sum,0,sizeof(sum));
}
int main()
{
	int t,n;
	cin>>t;
	int cas=0;
	while(t--)
	{
		scanf("%d",&n);
		cnt=0;
		for(int i=1;i<=n;i++)
		{
			scanf("%s",maps[i]+1);
			for(int j=1;j<=n;j++)
				if(maps[i][j]=='#')sum[i][j]=++cnt;
		}
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{
				if(maps[i][j]=='#')
				{
					for(int k=0;k<4;k++)
					{
						int x=i+dir[k][0];
						int y=j+dir[k][1];
						if(maps[x][y]=='#')
							G[sum[i][j]].push_back(sum[x][y]);
					}
				}
			}
		}
		printf("Case %d: %d\n",++cas,slove()/2);
		init();
	}
}

D:

Kindergarten

Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1540    Accepted Submission(s): 811

Problem Description

In a kindergarten, there are a lot of kids. All girls of the kids know each other and all boys also know each other. In addition to that, some girls and boys know each other. Now the teachers want to pick some kids to play a game, which need that all players know each other. You are to help to find maximum number of kids the teacher can pick.

Input

The input consists of multiple test cases. Each test case starts with a line containing three integers
G, B (1 ≤ G, B ≤ 200) and M (0 ≤ M ≤ G × B), which is the number of girls, the number of boys and
the number of pairs of girl and boy who know each other, respectively.
Each of the following M lines contains two integers X and Y (1 ≤ X≤ G,1 ≤ Y ≤ B), which indicates that girl X and boy Y know each other.
The girls are numbered from 1 to G and the boys are numbered from 1 to B.

The last test case is followed by a line containing three zeros.

Output

For each test case, print a line containing the test case number( beginning with 1) followed by a integer which is the maximum number of kids the teacher can pick.

Sample Input

2 3 3 1 1 1 2 2 3 2 3 5 1 1 1 2 2 1 2 2 2 3 0 0 0

Sample Output

Case 1: 3 Case 2: 4

 二分图的最大独立点集

普通图的最大团=补图的最大独立点集=所有节点数-二分图中最大匹配数(补图为二分图)

#include<bits/stdc++.h>
using namespace std;
const int N=220;
int vis[N],part[N];
int ma[N][N];
int n,m,k;
bool dfs(int x)
{
	for(int i=1;i<=m;i++)
	{
		if(ma[x][i]&&!vis[i])
		{
			vis[i]=1;
			if(!part[i]||dfs(part[i]))
			{
				part[i]=x;
				return 1;
			}
		}
	}
	return 0;
}
int slove()
{
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		memset(vis,0,sizeof(vis));
		if(dfs(i)) ans++;
	}
	return ans;
}
int main()
{
	int cas=0;
	while(cin>>n>>m>>k&&n&&m&&k)
	{
		memset(part,0,sizeof(part));
		memset(ma,1,sizeof(ma));
		for(int i=1;i<=k;i++)
		{
			int u,v;
			scanf("%d%d",&u,&v);
			ma[u][v]=0; 
		}
		printf("Case %d: %d\n",++cas,n+m-slove());
	}
}

E

Fire Net

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 16829    Accepted Submission(s): 10232

Problem Description

Suppose that we have a square city with straight streets. A map of a city is a square board with n rows and n columns, each representing a street or a piece of wall. 

A blockhouse is a small castle that has four openings through which to shoot. The four openings are facing North, East, South, and West, respectively. There will be one machine gun shooting through each opening. 

Here we assume that a bullet is so powerful that it can run across any distance and destroy a blockhouse on its way. On the other hand, a wall is so strongly built that can stop the bullets. 

The goal is to place as many blockhouses in a city as possible so that no two can destroy each other. A configuration of blockhouses is legal provided that no two blockhouses are on the same horizontal row or vertical column in a map unless there is at least one wall separating them. In this problem we will consider small square cities (at most 4x4) that contain walls through which bullets cannot run through. 

The following image shows five pictures of the same board. The first picture is the empty board, the second and third pictures show legal configurations, and the fourth and fifth pictures show illegal configurations. For this board, the maximum number of blockhouses in a legal configuration is 5; the second picture shows one way to do it, but there are several other ways. 

专题1 二分图 [Cloned](日常刷专题)_c++

Your task is to write a program that, given a description of a map, calculates the maximum number of blockhouses that can be placed in the city in a legal configuration. 

Input

The input file contains one or more map descriptions, followed by a line containing the number 0 that signals the end of the file. Each map description begins with a line containing a positive integer n that is the size of the city; n will be at most 4. The next n lines each describe one row of the map, with a '.' indicating an open space and an uppercase 'X' indicating a wall. There are no spaces in the input file. 

Output

For each test case, output one line containing the maximum number of blockhouses that can be placed in the city in a legal configuration.

Sample Input

4

.X..

....

XX..

....

2

XX

.X

3 .X.

X.X

.X.

3

...

.XX

.XX

4

....

....

....

....

0

Sample Output\

5

1

5

2

4

这个题。跟二分图专题有关?爆搜就是的了,反正n不大于4.

简单说一下题意:给了一个最大4x4的格子图,内置有墙,现在要求在里面放置碉堡(碉堡无限射距,且会互相),但是打不穿墙体.也就是说如果两个碉堡之间没有墙则不能放在同行或者同列. 

#include<bits/stdc++.h>
using namespace std;
char ma[8][8];
int n,ans; 
bool valid(int x,int y)
{
	for(int i=x-1;i>=0;i--)
	{
		if(ma[i][y]=='o') return 0;
		if(ma[i][y]=='X') break;
	}
	for(int i=y-1;i>=0;i--)
	{
		if(ma[x][i]=='o') return 0;
		if(ma[x][i]=='X') break;
	}
	return 1;
}
void dfs(int k,int num)
{
	if(k==n*n)
	{
		ans=max(ans,num);
		return ;
	}
	int x=k/n;
	int y=k%n;
	if(ma[x][y]=='.'&&valid(x,y))
	{
		ma[x][y]='o';
		dfs(k+1,num+1);
		ma[x][y]='.';
	}
	dfs(k+1,num);
}
int main()
{
	while(cin>>n&&n)
	{
		ans=0;
		for(int i=0;i<n;i++)
			scanf("%s",ma[i]);
		dfs(0,0);
		printf("%d\n",ans);
	}
}

 

F

Air Raid
Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 6987    Accepted Submission(s): 4630
Problem Description

Consider a town where all the streets are one-way and each street leads from one intersection to another. It is also known that starting from an intersection and walking through town's streets you can never reach the same intersection i.e. the town's streets form no cycles.
With these assumptions your task is to write a program that finds the minimum number of paratroopers that can descend on the town and visit all the intersections of this town in such a way that more than one paratrooper visits no intersection. Each paratrooper lands at an intersection and can visit other intersections following the town streets. There are no restrictions about the starting intersection for each paratrooper.

Input

Your program should read sets of data. The first line of the input file contains the number of the data sets. Each data set specifies the structure of a town and has the format:
no_of_intersections
no_of_streets
S1 E1
S2 E2
......
Sno_of_streets Eno_of_streets
The first line of each data set contains a positive integer no_of_intersections (greater than 0 and less or equal to 120), which is the number of intersections in the town. The second line contains a positive integer no_of_streets, which is the number of streets in the town. The next no_of_streets lines, one for each street in the town, are randomly ordered and represent the town's streets. The line corresponding to street k (k <= no_of_streets) consists of two positive integers, separated by one blank: Sk (1 <= Sk <= no_of_intersections) - the number of the intersection that is the start of the street, and Ek (1 <= Ek <= no_of_intersections) - the number of the intersection that is the end of the street. Intersections are represented by integers from 1 to no_of_intersections.
There are no blank lines between consecutive sets of data. Input data are correct.

 

Output

The result of the program is on standard output. For each input data set the program prints on a single line, starting from the beginning of the line, one integer: the minimum number of paratroopers required to visit all the intersections in the town.

 

Sample Input

2

4

3

3 4

1 3

2 3

3

3

1 3

1 2

2 3

Sample Output

2
 1

这题是属于 最小不相交路径覆盖。

最小可相交路径覆盖以后待补.........

题目意思:

题目描述:城镇里的街道从一个交叉口连接到另一个交叉口,街道都是单向的,并且从一个交叉口沿着街道出发不会回到相同的交叉口。伞兵降临在城镇的一个交叉口并可以沿着街道走向另一个没有被其他伞兵走过的交叉口,问城镇中的所有交叉口都被伞兵走过的情况下至少需要多少名伞兵。

题目的大意是在一个有向无环中,从一些顶点出发,能遍历图上的所有顶点,要求初始选择的顶点数最少且顶点不重复遍历。

 

做法:将每个点都分成两个顶点,一个在左,一个在右。若Vi到Vj有一条有向边,那就在左边的Vi连一条线到右边的Vj。

这样就构造了一个路径覆盖问题所对应的二分图形式。

 

前面的结论:有向无环图的最小路径覆盖=节点数-其拆点后对应二分图的最大匹配数

AC代码:
 

#include<bits/stdc++.h>
using namespace std;
const int N=150;
int vis[N],part[N];
int ma[N][N],t,n,m;
bool find(int x)
{
	for(int i=1;i<=n;i++)
	{
		if(ma[x][i]&&!vis[i])
		{
			vis[i]=1;
			if(!part[i]||find(part[i]))
			{
				part[i]=x;
				return 1;
			}
		}
	}
	return 0;
}
int slove()
{
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		memset(vis,0,sizeof(vis));
		if(find(i)) ans++;
	}
	return ans;
}
int main()
{
	cin>>t;
	while(t--)
	{
		memset(part,0,sizeof(part));
		memset(ma,0,sizeof(ma));
		scanf("%d%d",&n,&m);
		for(int i=1;i<=m;i++)
		{
			int u,v;
			scanf("%d%d",&u,&v);
			ma[u][v]=1;
		}
		printf("%d\n",n-slove());
	}
}

G:

The Accomodation of Students

There are a group of students. Some of them may know each other, while others don't. For example, A and B know each other, B and C know each other. But this may not imply that A and C know each other. 

Now you are given all pairs of students who know each other. Your task is to divide the students into two groups so that any two students in the same group don't know each other.If this goal can be achieved, then arrange them into double rooms. Remember, only paris appearing in the previous given set can live in the same room, which means only known students can live in the same room. 

Calculate the maximum number of pairs that can be arranged into these double rooms. 

Input

For each data set: 
The first line gives two integers, n and m(1<n<=200), indicating there are n students and m pairs of students who know each other. The next m lines give such pairs. 

Proceed to the end of file. 
 

Output

If these students cannot be divided into two groups, print "No". Otherwise, print the maximum number of pairs that can be arranged in those rooms. 

Sample Input

4 4
1 2
1 3
1 4
2 3
6 5
1 2
1 3
1 4
2 5
3 6

Sample Output

No
3

判断能分成两个团体,团体之间的人都互不认识(二分图判定)。每两个认识的开一间双人房,最多开几间双人房(二分图最大匹配)

下面的二分图匹配我没有按照我之前整理的模板打,是按照自己的理解打的,比较的长、不整洁。

//染色判定二分图
#include<bits/stdc++.h>
using namespace std;
const int N=250;
int ma[N][N],n,m,vis[N],du[N],part[N];
vector<int>G[N];
bool flag;
void color(int x,int num)
{
	vis[x]=1;
	for(int i=0;i<G[x].size();i++)
	{
		int v=G[x][i];
		if(du[v]==-1) 
		{
			du[v]=num;
			color(v,!num); 
		}
		else
		{
			if(du[x]==du[v]) 
			{
				flag=0;
				return ;
			}
		}
	}
}
bool find(int x)
{
	for(int i=0;i<G[x].size();i++)
	{
		int v=G[x][i];
		if(!vis[v])
		{
			vis[v]=1;
			if(!part[v]||find(part[v]))
			{
				part[v]=x;
				return 1;
			}
		}
	}
	return 0;
}
int slove()
{
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		memset(vis,0,sizeof(vis));
		if(find(i)) ans++;
	}
	return ans;
}
int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		flag=1;
		memset(du,-1,sizeof(du));
		memset(vis,0,sizeof(vis));
		memset(part,0,sizeof(part));
		for(int i=0;i<=n;i++) G[i].clear();
		for(int i=1;i<=m;i++)
		{
			int u,v;
			scanf("%d%d",&u,&v);
			G[u].push_back(v);
			G[v].push_back(u);
		}
		for(int i=1;i<=n;i++)
		{
			if(!vis[i])
			{
				du[i]=0;
				vis[i]=1;
				color(i,1);
			}
		}
		if(flag)
		{
			//printf("Yes\n");
			//实现最大匹配
			printf("%d\n",slove()/2); 
		}
		else printf("No\n");
	}
	
}

H:棋盘游戏

小希和Gardon在玩一个游戏:对一个N*M的棋盘,在格子里放尽量多的一些国际象棋里面的“车”,并且使得他们不能互相,这当然很简单,但是Gardon限制了只有某些格子才可以放,小希还是很轻松的解决了这个问题(见下图)注意不能放车的地方不影响车的
所以现在Gardon想让小希来解决一个更难的问题,在保证尽量多的“车”的前提下,棋盘里有些格子是可以避开的,也就是说,不在这些格子上放车,也可以保证尽量多的“车”被放下。但是某些格子若不放子,就无法保证放尽量多的“车”,这样的格子被称做重要点。Gardon想让小希算出有多少个这样的重要点,你能解决这个问题么? 

 

Input

输入包含多组数据, 
第一行有三个数N、M、K(1<N,M<=100 1<K<=N*M),表示了棋盘的高、宽,以及可以放“车”的格子数目。接下来的K行描述了所有格子的信息:每行两个数X和Y,表示了这个格子在棋盘中的位置。 

Output

对输入的每组数据,按照如下格式输出: 
Board T have C important blanks for L chessmen. 

Sample Input

3 3 4
1 2
1 3
2 1
2 2
3 3 4
1 2
1 3
2 1
3 2

Sample Output

Board 1 have 0 important blanks for 2 chessmen.
Board 2 have 3 important blanks for 3 chessmen.

这个题应该是属于二分图比较妙的相关题了。

我看了半天是真不会,然后百度了一个:来自:javascript:void(0)

专题1 二分图 [Cloned](日常刷专题)_二分图_02

首先缩点建图那里是真的可以。

2是求重要点居然可以这样求,学到了学到了。

//每一行和每一列看成一个点。每一行或每一列只能有一个棋子
//不就是二分图的形式吗。 
#include<bits/stdc++.h>
using namespace std;
const int N=120;
int ma[N][N],vis[N],part[N];
int n,m,k;
bool find(int x)
{
	for(int i=1;i<=m;i++)
	{
		if(ma[x][i]&&!vis[i])
		{
			vis[i]=1;
			if(!part[i]||find(part[i]))
			{
				part[i]=x;
				return 1;
			}
		}
	}
	return 0;
}
int slove()
{
	int ans=0;
	memset(part,0,sizeof(part));
	for(int i=1;i<=n;i++)
	{
		memset(vis,0,sizeof(vis));
		if(find(i))	ans++;
	}
	return ans;
}
int main()
{
	int cas=0;
	while(~scanf("%d%d%d",&n,&m,&k))
	{
		memset(part,0,sizeof(part));
		memset(ma,0,sizeof(ma));
		for(int i=1;i<=k;i++)
		{
			int u,v;
			scanf("%d%d",&u,&v);
			ma[u][v]=1;
		}
		int ans=slove();
		int num=0;
		//printf("ans\n");
		for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
		{
			if(ma[i][j])
			{
				ma[i][j]=0;
				int a1=slove();
				if(a1<ans) num++;
				ma[i][j]=1;
			}
		}
		printf("Board %d have %d important blanks for %d chessmen.\n",++cas,num,ans);
	}
}

最后一个题了。

I:Swap

 

Given an N*N matrix with each entry equal to 0 or 1. You can swap any two rows or any two columns. Can you find a way to make all the diagonal entries equal to 1?

Input

There are several test cases in the input. The first line of each test case is an integer N (1 <= N <= 100). Then N lines follow, each contains N numbers (0 or 1), separating by space, indicating the N*N matrix.

Output

For each test case, the first line contain the number of swaps M. Then M lines follow, whose format is “R a b” or “C a b”, indicating swapping the row a and row b, or swapping the column a and column b. (1 <= a, b <= N). Any correct answer will be accepted, but M should be more than 1000. 

If it is impossible to make all the diagonal entries equal to 1, output only one one containing “-1”. 

Sample Input

2
0 1
1 0
2
1 0
1 0

Sample Output

1
R 1 2
-1

这题建图和上一个题是一样的思路

不过我不会,只好百度了

专题1 二分图 [Cloned](日常刷专题)_i++_03现在才知道,原来二分图的最大匹配的part【】数组居然自带路径,可以根据需求输出。

很显然这题不是完美匹配就是-1..至于怎么输出路径。看代码

#include<bits/stdc++.h>
using namespace std;
const int N=120;
int ma[N][N],vis[N],part[N];
int ans[N],n;
bool find(int x)
{
	for(int i=1;i<=n;i++)
	{
		if(ma[x][i]&&!vis[i])
		{
			vis[i]=1;
			if(!part[i]||find(part[i]))
			{
				part[i]=x;
				return 1;
			}
		}
	}
	return 0;
}
int slove()
{
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		memset(vis,0,sizeof(vis));
		if(find(i)) ans++;
	}
	return ans;
}
int main()
{
	while(~scanf("%d",&n)&&n)
	{
		memset(part,0,sizeof(part));
		memset(ans,0,sizeof(ans));
		for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++) 
		scanf("%d",&ma[i][j]);
		int num=slove();
		if(num!=n)
		{
			printf("-1\n");
			continue;
		}
		int cnt=0;
		for(int i=1;i<=n;i++) ans[part[i]]=i;
		for(int i=1;i<=n;i++)
		{
			if(ans[i]!=i)//i行要交换 
			{
				for(int j=i+1;j<=n;j++)
				{
					if(ans[j]==i)// 与j行交换 
					{
						swap(ans[i],ans[j]);
						cnt++;
					}
				}
			}
		}
		printf("%d\n",cnt);
		for(int i=1;i<=n;i++) ans[part[i]]=i;
		for(int i=1;i<=n;i++)
		{
			if(ans[i]!=i)//i要交换 
			{
				for(int j=i+1;j<=n;j++)
				{
					if(ans[j]==i)//与j交换 
					{
						printf("R %d %d\n",i,j);
						swap(ans[i],ans[j]);
						//cnt++;
					}
				}
			}
		}
	}
}