poj2513

这道题目的意思很简单就是给定一系列的stick,每个stick的两端都有一个颜色(两端的颜色不同,并且每个stick的颜色都不完全相同)。问能否将这些stick首尾链接起来,使得相连处的颜色相同。这题的关键就是转化,将每种颜色都看作一个顶点,而每一个stick都看作一条边。这样就可以构成一个无向图了。而问题就可以转化为在这个无向图中是否存在一条欧拉通路或欧拉回路了。判断一个无向图是否为欧拉路的条件是:

1)无向图中所有顶点的度都是偶数或存在且仅存在两个为奇数的顶点

2)无向图为连通图

判断一个图是否为连通图用并查集解决。判断度数为偶数或奇数则记录顶点度数就可以了。这里存在一个核心问题:

并查集是存储结构为整形数组(形如set[i]=i),而这里每个顶点都是一个字符串,怎么样可以将字符串和数字一一对应起来,这是关键问题。

这里提供两种思路:

1)第一种就是用map映射,大致说一下思路:主要存储结构:

map(string,bool) exist//记录该字符串是否出现过

map(string,index) reflect//记录该字符串一一对应的数字

set[index]=index;//并查集数组

num[index]//记录数字的个数

首先设置一个全局变量count=1

对每一个没有出现过的颜色color三种结构,exist[color]=1,reflect[color]=count,set[count]=count;count++;

对出现过的颜色,则用reflect[color]来获取对应的数字,然后用并查集来合并这两个数字。对应的几何特征就是创建了一条边,同时num[index]++,相应的数字个数增加

2)利用字典树

利用字典树来产生于字符串一一对应的数字,后面的操作和上述基本上一样。

最后就是判断条件是否成立了。

其实这题的难点就是如何将题目的问题进行转换,另外就是利用字典数将颜色串与数字一一对应起来,下面是代码:

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
#define Maxx(a,b) (a)>(b)?(a):(b)
#define Minn(a,b) (a)<(b)?(a):(b)
#define Max 500010
char top[12];
char end[12];
int num[Max];
int set[Max];
int Count=1;
typedef struct Node{
	bool flag;
	int index;
	struct Node *next[26];
}node,*npivot;
int find(int x){
	int i=x;
	while(x!=set[x])
		x=set[x];
    int temp;
	while(i!=x){
		temp=set[i];
		set[i]=x;
		i=temp;
	}
	return x;
}
int Insert_heap(npivot root,char *source){
	npivot pivot=root;
	char *index=source;
	while(*index!='\0'){
		int temp=*index-'a';
		if(!pivot->next[temp]){
			pivot->next[temp]=(npivot)malloc(sizeof(node));
			pivot->next[temp]->flag=0;
			memset(pivot->next[temp]->next,0,sizeof(pivot->next[temp]->next));
			//for(int i=0;i<26;i++)
				//pivot->next[temp]->next[i]=NULL;
		}
		pivot=pivot->next[temp];
		index++;
	}
	if(pivot->flag){
		return pivot->index;
	}
	else{
		set[Count]=Count;
		pivot->index=Count;
		pivot->flag=1;
		Count++;
		return pivot->index;
	}
}	
int main(){
	memset(num,0,sizeof(num));
	npivot root=(npivot)malloc(sizeof(node));
	root->flag=0;
	memset(root->next,0,sizeof(root->next));
	//for(int i=0;i<26;i++)
		//root->next[i]=NULL;
	while(cin >> top >> end){
	    int x=Insert_heap(root,top);
		int y=Insert_heap(root,end);
	    num[x]++;
		num[y]++;
		int a=find(x);
		int b=find(y);
		if(a!=b)
			set[Maxx(a,b)]=Minn(a,b);
	}
	int sum=0;
	for(int i=1;i<Count;i++)
		if(num[i]%2!=0)
		  sum++;
	if(sum!=0 && sum!=2){
		//cout << "Impossible" << endl;
		printf("Impossible\n");
	    return 0;
	}
	int Inf=find(1);
	int i;
	for(i=1;i<Count;i++)
		if(find(i)!=Inf)
			break;
	if(i!=Count)
       // cout << "Impossible" << endl;
		printf("Impossible\n");
	else
		//cout << "Possible" << endl;
		printf("Possible\n");
	    
	return 0;
}
				
			
		


 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值