1. 程式人生 > >JZOJ-senior-5934. 【NOIP2018模擬10.29】列隊

JZOJ-senior-5934. 【NOIP2018模擬10.29】列隊

Time Limits: 1000 ms Memory Limits: 262144 KB

Description

Sylvia是一個熱愛學習的女孩子。

在平時的練習中,他總是能考到std以上的成績,前段時間,他參加了一場練習賽,眾所周知,機房是一個 的方陣。這天,他又打爆了std,感到十分無聊,便想要hack機房內同學的程式,他會挑選一整行或一整列的同學進行hack ( 而且每行每列只會hack一次 ),然而有些同學不是那麼好惹,如果你hack了他兩次,他會私下尋求解決,Sylvia十分害怕,只會hack他們一次。假設Sylvia的水平十分高超,每次hack都能成功,求他最 多能hack多少次?

Input

第一行兩個數 表示機房的大小和不好惹的同學個數
接下來x行,每行兩個數 表示不好惹的同學座標

Output

一個數表示最多hack多少次

Sample Input

2 1
1 1

Sample Output

6

樣例說明
他可以hack第一行、第二行、第二列一共6次

Data Constraint

資料規模和約定
對於20%的資料 n<=10, x<=100
對於40%的資料 n<=20 , x<=400
對於100%的資料 n<=1000 , x<=4000
1<=x,y<=n且同一個點不會重複出現

Solution

  • 行列棋盤是二分圖的經典模型
  • 對於一個不好惹的同學的位置 ( x , y ) (x,y) ,只能選它所在行或列
  • 我們將行看成左邊的點,列看做右邊的點
  • 有人的格子就將它所在的行和列連邊
  • 題目問最多能選出多少個點,使得有連邊的點不在同一個集合
  • 問題轉化為二分圖上的最大獨立集問題
  • 最大獨立集點數=總點數-最大匹配數
  • 匈牙利演算法即可

Code

#include<algorithm>
#include<cstring>
#include<cstdio>

#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fd(i,a,b) for(int i=a;i>=b;--i)

using namespace std;

const int N=1010;
int n,m,x,y,cnt;
int c[N],v[N],b[N][N];

bool find(int x)
{
	fo(j,1,n) if(b[x][j]&&!v[j])
	{
		v[j]=1;
		if(!c[j]||find(c[j]))
		{
			c[j]=x;
			return 1;
		}
	}
	return 0;
}

int main()
{
	freopen("phalanx.in","r",stdin);
	freopen("phalanx.out","w",stdout);
	scanf("%d%d",&n,&m);
	fo(i,1,m) scanf("%d%d",&x,&y),b[x][y]=1;
	fo(i,1,n)
	{
		memset(v,0,sizeof(v));
		if(find(i)) ++cnt;
	}
	printf("%d",(2*n-cnt)*n);
}