您的位置:首页 > 其它

BZOJ 1854 [Scoi2010]游戏

2016-09-25 14:48 501 查看
并查集 或 二分图匹配

这题复杂度错误的算法竟然跑得比正解快

错误的算法(1):用装备的两种属性向装备连边,跑二分图匹配即可,注意题目要求是连续攻击,所以一旦匹配不成功就要退出。为了优化时间,vis数组开成int,以免去memset的时间

正确的算法(2):把每一个装备考虑成一条边,它的两个属性考虑成边两端点的编号。使用装备相当于删除这条边。于是可以发现如果某连通块图中有环,那么环上的点必定都可以取到。如果是树结构,让编号最大的取不到即可。

二分图匹配

#include<cstdio>
#include<cstring>
#define W 10005
#define N 1000005
#define reg register
#define getc() (S == T && (T = (S = B) + fread(B, 1, 1 << 15, stdin), S == T) ? EOF : *S++)
using namespace std;
int a
, h
, tot=0;
char B[1 << 15], *S = B, *T = B;
inline int in()
{
reg char ch=getc();
reg int cnt = 0;
while(ch<'0'||ch>'9')ch=getc();
while(ch>='0'&&ch<='9')cnt=(cnt<<3)+(cnt<<1)+ch-'0', ch=getc();
return cnt;
}
struct edge{int next,to;}e[N<<1];
int ecnt=0, last[W], mx=0, mat
, times, vis
;
void add(int a, int b)
{
e[++ecnt]=(edge){last[a],b};
last[a]=ecnt;
}
bool find(int x)
{
for(int i = last[x]; i; i=e[i].next)
{
int y=e[i].to;
if(vis[y]==times)continue;
vis[y]=times;
if(!mat[y]||find(mat[y]))
{
mat[y]=x;
return true;
}
}
return false;
}
int solve()
{
for(int i = 1; i <= mx; i++)
{
times=i;
if(!find(i))
return i-1;
}
return mx;
}
int main()
{
int n=in();
for(int i = 1, a, b; i <= n; i++)
{
a=in(); b=in();
add(a,i); add(b,i);
if(a>mx)mx=a;
if(b>mx)mx=b;
}
printf("%d\n",solve());
}


并查集

#include<cstdio>
#include<algorithm>
#define N 10005
using namespace std;
int f
;
int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
bool flag
;
int main()
{
int n; scanf("%d",&n);
for(int i = 1; i < N; i++)
f[i]=i;
for(int i = 1, a, b; i <= n; i++)
{
scanf("%d%d",&a,&b);
int f1=find(a), f2=find(b);
if(f1!=f2)
{
if(f1<f2)swap(f1,f2);
flag[f2]=1;
f[f2]=f1;
}
else
flag[f1]=1;
}
for(int i = 1; i <= 10001; i++)
if(!flag[i])
{
printf("%d\n",i-1);
break;
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: