并查集

 

UVALive 5789

题意 给你1到n的区间,m组操作

每组操作有a,b两个数字, 指将[a,b]变为1,求左右两边最靠近[a,b]区间为0的位置

此题所给的m组区间不会相交,开始读题是看错了 ,写了个可能相交的

View Code
#include<iostream>
#include<cstring>
#include <cstdio>
#include<string>
#include<queue>
#include<vector>
#include<map>
#include <set>
#include<ctime>
#include<cmath>
#include <cstdlib>
#include<algorithm>
#include <iomanip>
#include <bitset>
using namespace std;
#define LL long long

const int MAX = 110000;
const int nMAX =10;
const int mMAX =300;
const int INF =((1<<31)-1);
const int MOD= 1000000007;

int L[MAX],R[MAX],Start,End;
int findR(int x){
if(R[x]==-1) return -1;
if(x==R[x]) return x;
return R[x]=findR(R[x]);
}
int findL(int x){
if(L[x]==-1) return -1;
if(x==L[x]) return x;
return L[x]=findL(L[x]);
}
void init(int _Start,int _End){
Start=_Start; End=_End;
fill(L+Start,L+End+1,-1);
fill(R+Start,R+End+1,-1);
}
void add(int u,int v){
int nxt,left,right,l,r;
if(u-1>=Start&&findL(u-1)!=-1) left=findL(u-1);
else left=u;

if(v+1<=End&&findR(v+1)!=-1) right=findR(v+1);
else right=v;

for(l=left,r=right ;l<=r;l=nxt){
if(findR(l)!=-1&&findR(l)!=l) nxt=findR(l);
else nxt=l+1;
R[l]=r;
}
for(l=left,r=right ;l<=r;r=nxt){
if(findL(r)!=-1&&findL(r)!=r) nxt=findL(r);
else nxt=r-1;
L[r]=l;
}
}
int findL_no(int left) { return findL(left)-1; }
int findR_no(int right) { return findR(right)+1; }
int main(){
int n,m;
while(scanf("%d%d",&n,&m)){
if(!n&&!m) return 0;
init(1,n);
while(m--){
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
if(findL_no(u)>=1) printf("%d ",findL_no(u));
else printf("* ");
if(findR_no(v)<=n) printf("%d",findR_no(v));
else printf("*");
printf("\n");
}
printf("-\n");
}
}

 

poj 1417

题目大意:
一共有p1+p2个人,分成两组,一组p1,一组p2。给出N个条件,格式如下:
x y yes表示x和y分到同一组
x y no表示x和y分到不同组
问分组情况是否唯一,若唯一则输出方案,否则输出no。保证不存在矛盾条件,但是有可能出现x=y的情况。
题目分析:
先用并查集确定好联通块,然后就是把每一组相互关系确定的点分成两部分,记录点数,把它们抽象成两种容量的背包。
每一组有两个背包,用且只能用一个,问达到p1,p2状态的方案是否唯一,若唯一则输出。典型的背包问题。

View Code
#include<iostream>
#include<cstring>
#include<map>
using namespace std;
const int maxn = 605;
int p[maxn],r[maxn];
int find(int x){
if(p[x]==x) return x;
int rx=find(p[x]);
r[x]=(r[p[x]]+r[x])%2;
return p[x]=rx;
}
void union_set(int a,int b,int s){
int ra=find(a) , rb=find(b);
if(ra!=rb) {
p[ra]=rb;
r[ra]=(s-r[a]+r[b]+2)%2;
}
}
struct info{
int x,y,z1,z2;
}scc[maxn];
int vis[maxn],dp[maxn][maxn];
bool ans[maxn];
info pre[maxn][maxn];
int main(){
int m,p1,p2;
while(scanf("%d%d%d",&m,&p1,&p2)!=EOF){
if(!m&&!p1&&!p2) return 0;
for(int i=0;i<=p1+p2;i++){
p[i]=i; r[i]=0;
}
while(m--){
char str[10]; int a,b;
scanf("%d%d%s",&a,&b,str);
if(!strcmp(str,"yes")) union_set(a,b,0);
else union_set(a,b,1);
}
int cnt=0;
memset(vis,0,sizeof(vis));
memset(dp,-1,sizeof(dp));
memset(scc,0,sizeof(scc));
memset(pre,0,sizeof(pre));

for(int i=1;i<=p1+p2;i++){
int t=find(i);
if(!vis[t]) cnt++,vis[t]=cnt,scc[vis[t]].z1=t;
if(r[i]==0) scc[vis[t]].x++;
else scc[vis[t]].y++;
}

dp[0][0]=1;
for(int i=1;i<=cnt;i++){
for(int j=0;j<=p1;j++){
if(j-scc[i].x>=0&&dp[i-1][j-scc[i].x]!=-1){
if(dp[i][j]==-1) dp[i][j]=0;
dp[i][j]+=dp[i-1][j-scc[i].x];
pre[i][j].z1=scc[i].z1, pre[i][j].y=j-scc[i].x , pre[i][j].z2=0;
}
if(j-scc[i].y>=0&&dp[i-1][j-scc[i].y]!=-1){
if(dp[i][j]==-1) dp[i][j]=0;
dp[i][j]+=dp[i-1][j-scc[i].y];
pre[i][j].z1=scc[i].z1, pre[i][j].y=j-scc[i].y , pre[i][j].z2=1;
}
if(dp[i][j]>1) dp[i][j]=2;
}
}

if(dp[cnt][p1]!=1) printf("no\n");
else{
memset(ans,0,sizeof(ans));
int next=p1;
for(int i=cnt;i>=0;i--){
for(int j=1;j<=p1+p2;j++)
if(p[j]==pre[i][next].z1&&r[j]==pre[i][next].z2) ans[j]=1;
next=pre[i][next].y;
}
for(int i=1;i<=p1+p2;i++)
if(ans[i]) printf("%d\n",i);
printf("end\n");
}
}return 0;
}
//测试数据
//1 1 0
//1 1 yes
//3 2 0
//1 2 no
//2 2 yes
//1 1 yes

//3 2 0
//1 1 yes
//2 2 yes
//1 1 yes

//7 4 2
//2 3 no
//3 4 no
//4 3 no
//5 5 yes
//5 3 no
//5 5 yes
//1 5 yes
//0 1 0



posted @ 2012-04-08 11:02  HaoHua_Lee  阅读(177)  评论(0编辑  收藏  举报