分析:
Method1:二分图匹配
我们建图满足的要求是可以保证每个武器只能使用一次,第一想法是把一个武器拆成两个点,但是这样怎么保证每个点只选一次呢?首先就要在两个点之间建立联系…连边?然后呢?只能选其中一个点?感觉好像不好搞的样子….
或许我们可以借助一个点把这两个点建立联系,就是从一个点向这两个点连边,那么只能选一条边?感觉像是二分图匹配?
bingo!
我们把武器编号作为左部节点,武器属性值作为右部节点,对于每个武器,向它的两个属性值连边,然后从1到10000去跑二分图匹配,如果匹配不了就输出ans
代码如下:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std;
const int maxn=1000010+5;
int n,hd[maxn],to[maxn*2],nxt[maxn*2],cnt,vis[maxn],pre[maxn],ans,sta;
inline void add(int x,int y){
to[cnt]=y;
nxt[cnt]=hd[x];
hd[x]=cnt++;
}
inline bool dfs(int root){
for(int i=hd[root];i!=-1;i=nxt[i])
if(vis[to[i]]!=sta){
vis[to[i]]=sta;
if(pre[to[i]]==-1||dfs(pre[to[i]])){
pre[to[i]]=root;
return true;
}
}
return false;
}
signed main(void){
cnt=sta=0;
scanf("%d",&n);
memset(hd,-1,sizeof(hd));
memset(vis,0,sizeof(vis));
memset(pre,-1,sizeof(pre));
for(int i=1,x,y;i<=n;i++)
scanf("%d%d",&x,&y),add(x,i),add(y,i);
ans=10000;
for(int i=1;i<=10000;i++){
sta++;
if(!dfs(i)){
ans=i-1;
break;
}
}
cout<<ans<<endl;
return 0;
}
Method2:并查集
在上一个方法中我们是用武器编号这个节点在两个属性值之间建立联系,我们也可以借助一条边把这两个属性值建立联系,可以理解为一条边代表一个武器,然后如果一个连通块中有一个n个节点的树,那么代表有n-1个武器可以使用,如果是一个环呢?代表n个武器可以使用…
如果每次加入的边是合并两个联通块
就把权值小的联通块并到权值大的联通块,然后给权值小的vis=true
如果不是就把该联通块的顶点的vis=true
这样就可以保证,如果一个大小为N联通块
=N-1条边构成,最大点的vis=false,其他为true
≥N条边构成,所有点的vis=true
然后最后只要一次扫描vis就可以得出答案了
代码如下:
(借用YOUSIKI童鞋的代码)
/*
* You Siki
* Born to be King!
*/
#include<cstdio>
#include<cstdlib>
#include<cstring>
//using namespace std;
const int LIMIT = 10000000;
char in[LIMIT], *p = in;
signed main(void) {
fread(p, 1, LIMIT, stdin);
register int n = 0;
while (*p < '0')++p;
while (*p >= '0')
n = n * 10 + *p++ - '0';
register bool visit[10005];
register short father[10005];
register short stack[10005], tot = 0;
memset(visit, 0, sizeof(visit));
for (register int i = 1; i <= 10000; ++i)father[i] = i;
for (register int i = 1, x, y; i <= n; ++i) {
x = y = 0;
while (*p < '0')++p;
while (*p >= '0')
x = x * 10 + *p++ - '0';
while (x ^ father[x])
stack[++tot] = x, x = father[x];
while (tot)father[stack[tot--]] = x;
while (*p < '0')++p;
while (*p >= '0')
y = y * 10 + *p++ - '0';
while (y ^ father[y])
stack[++tot] = y, y = father[y];
while (tot)father[stack[tot--]] = y;
if (x ^ y) {
if (x > y)
visit[visit[y] ? x : y] = true, father[y] = x;
else
visit[visit[x] ? y : x] = true, father[x] = y;
}
else visit[x] = true;
}
register int ans = 0;
while (visit[++ans]);
printf("%d\n", --ans);
}
by >_< NeighThorn