HDU 3812
来源:互联网 发布:社保报盘软件下载 编辑:程序博客网 时间:2024/06/03 22:05
求Sea到Sky的最长路,输出字典序最小的。
该题必须剪枝,属于强联通分量。
剪枝1:不知道算不算上的剪枝,首先DFS一下连通性,如果Sea到Sky是不连通的就根本不需要搜索了
剪枝2:对字符串排序后建图,先储存不重复的字符串,在转化成点建图..建图前排序字符串,这样就保证先搜出的路径是字典序最短的,更优的路径必须是长度大于它,这就省掉了在搜索过程中对字典序的判断
剪枝3:路径上的点必须满足一个条件,能经过不重复的点到起点,且不经过终点 对终点也同样如此.所以事先可以将这些无法到达的点标记出来,之后不要在这些点里搜索...
代码:
#include <cstdio>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <cstdlib>
using namespace std;
char word[20][20],s1[105][20],s2[105][20];
int ws,map[20][20],vis[20],vis2[20],res[20],bres[20],yes,sky,sea,rl;
void init(){
memset(map,0,sizeof map);
for(int i=1;i<=20;i++)strcpy(word[i],"\0");
ws=0;//点数
memset(res,0,sizeof res);
yes=0;
rl=0;
}
//搜连通
int dfslt(int p){
if(p==sky)return 1;
for(int i=1;i<=ws;i++){
if(!vis[i]&&map[p][i]){
vis[i]=1;
if(dfslt(i))return 1;
}
}
return 0;
}
//搜不可到达的点
int dfs2(int p,int dir){
if(p==dir)return 1;
for(int i=1;i<=ws;i++){
if(!vis2[i]&&!vis[i]&&map[p][i]){
vis2[i]=1;
if(dfs2(i,dir))return 1;
}
}
return 0;
}
int dfs(int step,int p){
if(step>ws)return 0;
if(res[step]==sky&&step>rl){
yes=1;
rl=step;
for(int i=0;i<=rl;i++){
bres[i]=res[i];
}
if(rl==ws)return 1;
return 0;
}
for(int i=1;i<=ws;i++){
if(!vis[i]&&map[p][i]==1){
vis[i]=1;
res[step+1]=i;
if(dfs(step+1,i))return 1;
vis[i]=0;
}
}
return 0;
}
int gwords(char *ss){
for(int i=1;i<=ws;i++){
if(strcmp(word[i],ss)==0){
return i;
}
}
ws++;
strcpy(word[ws],ss);
return ws;
}
int main(){
int cas;
scanf("%d",&cas);
for(int ca=1;ca<=cas;ca++){
init();
int n,a,b;
scanf("%d",&n);
//输入字符串 储存
for(int i=1;i<=n;i++){
scanf("%s%s",s1[i],s2[i]);
gwords(s1[i]),gwords(s2[i]);
}
//冒泡排序
char t[20];
for(int i=1;i<=ws-1;i++){
int ind=i;
for(int j=i+1;j<=ws;j++){
if(strcmp(word[j],word[ind])<0)ind=j;
}
if(ind!=i){
strcpy(t,word[ind]);
strcpy(word[ind],word[i]);
strcpy(word[i],t);
}
}
//建图 map[i][j]~按照字符串升序
for(int i=1;i<=n;i++){
a=gwords(s1[i]),b=gwords(s2[i]);
map[a][b]=map[b][a]=1;
}
//判单词是否存在
sky=-1,sea=-1;
for(int i=1;i<=ws;i++){
if(strcmp(word[i],"sky")==0)sky=i;
if(strcmp(word[i],"sea")==0)sea=i;
}
//判sea->sky是否可达
memset(vis,0,sizeof vis);
vis[sea]=1;
//如果不存在单词 或者两者不可达
if(sky==-1||sea==-1||!dfslt(sea)){
printf("Case %d: what a pity\n",ca);
continue;
}
memset(vis,0,sizeof vis);
//强力剪枝,去掉不可到达的点
for(int i=1;i<=ws;i++){
memset(vis2,0,sizeof vis2);
vis2[sea]=1;
if(!dfs2(i,sky))vis[i]=1;
}
for(int i=1;i<=ws;i++){
memset(vis2,0,sizeof vis2);
vis2[sky]=1;
if(!dfs2(i,sea))vis[i]=1;
}
//搜索
vis[sea]=1;
res[1]=sea;
dfs(1,sea);
//输出
if(yes){
printf("Case %d: %s",ca,word[bres[1]]);
for(int i=2;i<=rl;i++){
printf(" %s",word[bres[i]]);
}
printf("\n");
}else{
printf("Case %d: what a pity\n",ca);
}
}
return 0;
}
- HDU 3812
- hdu
- hdu
- HDU
- hdu ()
- hdu
- hdu
- HDU
- HDU
- hdu
- hdu
- HDU
- Hdu
- hdu
- hdu-
- hdu
- hdu
- hdu
- Cordic 算法入门
- @CL之家caoliu之家dizhi
- MongoDB(二)——安装配置了解
- 深入理解指针—>指针函数与函数指针的区别
- java 实践源码--并查集
- HDU 3812
- nike aRBI HMj Tq3Qm
- 读黑客与画家,吐槽的一些话——中国科学技术大学软件+冯开开+原创
- 通过show status 来优化MySQL数据库
- SHELL 学习
- 解决:centos 虚拟机上安装apache后,不能访问
- python的入门注意
- Android Animation动画(超详细)
- 2014秋C++第12周项目2参考-OJ平台题目中多种输入形式的处理