[bzoj1854][SCOI2010]游戏
Description
一个装备有两个属性,一个装备只能被使用一次,一次使用一种属性。攻击\(boss\)时需按属性\(1\)、属性\(2\)、属性\(3\)...属性\(k\)的顺序使用,问\(k\)最大为多少。
Input
输入的第一行是一个整数\(N\),表示有\(N\)种装备。接下来\(N\)行,是对这\(N\)种装备的描述,每行\(2\)个数字,表示第\(i\)种装备的\(2\)个属性值。
Output
输出一行,包括\(1\)个数字,表示\(k\)。
Sample Input
3
1 2
3 2
4 5
Sample Output
2
HINT
\(1\;\leq\;\)属性值\(\;\leq\;10000,N\;\leq\;1000000\).
Solution
由于一种装备只能使用一次,而且只有装备和属性值两种分类,就会想到二分图匹配。
将装备和属性值分成两个集合,将属性值向所属装备连一条边,判断当前\(k\),如果可匹配,判断\(k+1\),如果不可行,\(k-1\)就是答案。
如果使用匈牙利算法的话,\(used[\;]\)不能每次都重新赋值\(false\),会\(T\)(实测),而要将当前\(k\)作为判断标志(\(used[\;]=k\)为访问过)。
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define K 10001
#define N 1000001
#define M 2000001
using namespace std;
struct graph{
int nxt,to;
}e[M];
int g[K],u[N],fr[N],n,cnt,ans;
inline int read(){
int ret=0;char c=getchar();
while(!(c>='0'&&c<='9'))
c=getchar();
while(c>='0'&&c<='9'){
ret=ret*10+c-'0';
c=getchar();
}
return ret;
}
inline void addedge(int x,int y){
e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y;
}
inline bool match(int k){
for(int i=g[k];i;i=e[i].nxt)
if(u[e[i].to]!=ans){
u[e[i].to]=ans;
if(!fr[e[i].to]||match(fr[e[i].to])){
fr[e[i].to]=k;return true;
}
}
return false;
}
inline void init(){
n=read();
for(int i=1,k;i<=n;i++){
k=read();addedge(k,i);
k=read();addedge(k,i);
}
for(ans=1;ans<K;ans++){
if(!match(ans)) break;
}
printf("%d\n",--ans);
}
int main(){
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
init();
fclose(stdin);
fclose(stdout);
return 0;
}