二分图匹配。
左边的点表示属性,右边的点表示武器编号,每次读入将武器和对应属性之间连边,然后从1-10000枚举属性值,如果某个属性值没有匹配到武器那么就退出循环,输出上一个属性值。为了防止第10000属性也可以满足,要枚举到10001。另外笔者蒟蒻……第一遍交跑出个TLE,然后重新看了一下匈牙利发现,我们把vis数组的职能从bool类型改成了int类型,对于第k个属性值,每次访问到一个武器i时,如果vis[i]==k就说明本次搜索这个点已经搜过了,否则记录一下vis[i]=k,防止重复搜索,这样就可以不要每次都memset。
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
const int maxn=5000005;
int n,m,match[maxn],vis[maxn],x,y,k;
int node[maxn],next[maxn],head[maxn],tot;
int get(){
int p=0;char x=getchar();
while (x<'0' && x>'9') x=getchar();
while (x>='0' && x<='9') p=p*10+x-'0',x=getchar();
return p;
}
void add(int x,int y){
node[++tot]=y;
next[tot]=head[x];
head[x]=tot;
}
bool dfs(int x){
for (int i=head[x];i;i=next[i])
if (vis[node[i]]!=k){
vis[node[i]]=k;
if (!match[node[i]] || dfs(match[node[i]])){
match[node[i]]=x;
return 1;
}
}
return 0;
}
int main(){
n=get();tot=0;
memset(head,0,sizeof head);
memset(vis,0,sizeof vis);
for (int i=1;i<=n;i++){
x=get();y=get();
add(x,i);add(y,i);
}
for (k=1;k<=10001;k++)
if (!dfs(k)) break;
printf("%d",k-1);
return 0;
}