Hdu3812-Sea Sky(深搜+剪枝)

Sea and Sky are the most favorite things of iSea, even when he was a small child.  Suzi once wrote: white dew fly over the river, water and light draw near to the sky. What a wonderful scene it would be, connecting the two charming scenery. But iSea cannot ask help from God, or some other deities in China. The only mean he can use is imagination. 
For example, from sea, he can associate with love, from love, he can see sky in (strange logic, aha? leave him alone, we don't really care how he imagine since he is so weird). In this way, he connects "Sea" and "Sky" in mind, fulfills his goal.  However, he can only solve the puzzle with small number of words, when the connection increases, his brain will come to be a total mess. Now, can you smart guys help him? 
Now iSea gives you some word pairs he can associate, from any one of them to another. He wishes use the maximum word to make an association list, from “sea” to “sky”, of course, no word should appear in the list twice because it would lead to an infinite loop. Your task is to find a list, which contains the maximum word and every neighbor word can be connected in mind. If several solutions exist, find the lexicographically minimum one.  Lexicographical sequence is the order in one dictionary. For example, “cat” is less than “do”, and “do” is less than “dog”.
 

Input

The first line contains a single integer T, indicating the number of test cases.  Each test case begins with an integer N, then N lines follow, each line contains two words can be connected in mind. 
Technical Specification 
1. 1 <= T <= 50  2. 1 <= N <= 100  3. The number of different words and the length of words is no more than sixteen.
 

Output

For each test case, output the case number first, if cannot finish, output “what a pity”. Otherwise, output a word sequence with most words, separated by a blank.
 

Sample Input

3
2
sea love
sky love
7
sea pure
pure air
air white
sky white
pure holy
holy white
sky holy
3
sea blue
sky white
blue green
 

Sample Output

Case 1: sea love sky
Case 2: sea pure air white holy sky
Case 3: what a pity
 
题意: 给出N对字符串,每对字符串可以相连,问能否找到一条从sea到sky的字符串链,每个字符串只能出现一次,如果能,输出
长度最长的,如果有多解,输出字典序最小的。无解输出what a pity
 
解析: 刚开始还以为是个有环找最长路的图论题(然而我并不会写)。。。。。。看了别人题解才知道是深搜+剪枝。
对字符串排序标号,如果没有出现sea或者sky,直接无解,然后并查集一下,如果不在同一个集合,同样无解,然后判断每个点
(起点和终点除外)是否能到达起点和终点,不能的在搜的过程中直接不管,然后就是搜了,搜的过程中更新解,如果最大长度
已经用完了所有的字符串就没必要再搜了(最开始我没管这个超时了。。。。。。后来加了这个剪枝就过了)
 
代码
#include<cstdio>
#include<cstring>
#include<string>
#include<map>
#include<vector>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxn=202;
int N,id,be,en;
string S1[maxn],S[maxn];
int d[maxn];
int root(int a){ return d[a]==a?a:d[a]=root(d[a]); }
bool G[maxn][maxn];
int GetId(string& s) //找到下标
{
    for(int i=1;i<=id;i++) if(S[i]==s) return i;
    return 0;
}
bool input()
{
    N*=2;
    for(int i=1;i<=N;i++)
    {
        cin>>S1[i];
        S[i]=S1[i];
    }
    sort(S+1,S+N+1);  //排个序
    be=en=0;  //起点和终点编号
    id=1;
    for(int i=2;i<=N;i++)
    {
        if(S[i]!=S[id]) S[++id]=S[i];  //去重
        if(S[id]=="sea") be=id;
        if(S[id]=="sky") en=id;
    }
    if(!be||!en) return false; //没有sea或者sky
    for(int i=0;i<maxn;i++) d[i]=i;  //并查集
    memset(G,false,sizeof(G));
    for(int i=1;i<N;i+=2)
    {
        int a=GetId(S1[i]);  //下标
        int b=GetId(S1[i+1]);
        int ra=root(a);
        int rb=root(b);
        G[a][b]=G[b][a]=true;  //可连
        if(ra!=rb) d[rb]=ra; //合并
    }
    if(root(be)!=root(en)) return false; //不在同一集合
    return true;
}
bool vis[maxn],tvis[maxn];
int maxl,temp[maxn],ans[maxn];
bool dfs(int x,int step)
{
    vis[x]=true;
    temp[step]=x;
    if(x==en)  //到终点
    {
        if(step>maxl) //更新解
        {
            maxl=step;
            for(int i=0;i<=maxl;i++) ans[i]=temp[i];
        }
        if(step==id-1) return true; //用完所有的
    }
    for(int i=1;i<=id;i++)
        if(!vis[i]&&G[x][i])
    {
        if(dfs(i,step+1)) return true;
    }
    vis[x]=false;
    return false;
}
bool Reach(int x,int y)
{
    if(x==y) return true;
    for(int i=1;i<=id;i++)
        if(!tvis[i]&&!vis[i]&&G[x][i])
        {
            tvis[i]=true;
            if(Reach(i,y)) return true;
        }
    return false;
}
void solve()
{
    memset(vis,false,sizeof(vis));
    for(int i=1;i<=id;i++)
    {
        memset(tvis,false,sizeof(tvis));
        tvis[be]=true;
        if(!Reach(i,en)) vis[i]=true;  //能否到终点
    }
    for(int i=1;i<=id;i++)
    {
        memset(tvis,false,sizeof(tvis));
        tvis[en]=true;
        if(!Reach(i,be)) vis[i]=true; //能否到起点
    }
    maxl=0;  //最大长度
    dfs(be,0); //深搜
}
int main()
{
    int T,Case=0;
    cin>>T;
    while(T--)
    {
        cin>>N;
        if(!input())  //无解
        {
            printf("Case %d: what a pity\n",++Case);
            continue;
        }
        solve();
        printf("Case %d:",++Case);
        for(int i=0;i<=maxl;i++) cout<<" "<<S[ans[i]];
        cout<<endl;
    }
    return 0;
}
View Code

 

posted @ 2016-07-18 13:50  wust_ouyangli  阅读(204)  评论(0编辑  收藏  举报