D(1843): Jumping monkey

来源:互联网 发布:淘宝装修图片如何制作 编辑:程序博客网 时间:2024/05/16 04:45

Description

You are a hunter chasing a monkey in the forest, trying to shoot it down with your all-powerful automatic machine gun. The monkey is hiding somewhere behind the branches of one of the trees, out of your sight. You can aim at one of the trees and shoot; your bullets are capable of going through the branches and killing the monkey instantly if it happens to be in that tree. If it isn't, the monkey takes advantage of the time it takes you to reload and takes a leap into a neighbouring tree without you noticing. It never stays in the same place after a shot. You would like to find out whether there is an strategy that allows you to capture the monkey for sure, irrespective of its initial location and subsequent jumps. If so, you need to determine the shortest sequence of shots guaranteeing this.

  As an example, consider the situation in which there are only two neighboring trees in the forest (left hand side of Figure 2). It is then possible to make sure you capture the monkey by shooting twice at the same tree. Your first shot succeeds if the monkey happened to be there in the rst place. Otherwise, the monkey was behind the other tree and it will necessarily have moved when you shoot for the second time.

  However, depending on the shape of the forest it may not possible for you to ensure victory. One example of this is if there are three trees, all connected to one another (right hand side of Figure 2). No matter where you aim at, there are always two possible locations for the monkey at any given moment. (Note that here we are concerned with the worst-case scenario where the monkey may consistently guess your next target tree).

Input

  The input consists of several test cases, separated by single blank lines. Each test case begins with a line containing two integers n and m ( 1n211≤n≤21 ); n is the number of trees in the forest, and m is the number of adjacency relations between trees. Each of the following m lines contains two distinct integers between 0 and n-1(inclusive), the identifiers of the trees in an adjacent pair. The order of both trees within a pair carries no meaning, and no pair appears more than once. You may further assume that no tree is adjacent to itself, and there is always a path between any two trees in the forest.

  The test cases will finish with a line containing only two zeros (also preceded with a blank line).

Output

  Print a line for each test case. The line should contain the single word Impossible if the task is impossible. Otherwise, it must contain the shortest sequence of shots with the required property, in the format L:V1V2VLL:V1V2…VL , where LL is the length of the sequence, and V1,V2,,VLV1,V2,…,VL are space-separated integers containing the identifiers of the trees to shoot at in the right order. If several shortest sequences exist, print the lexicographically smallest one. (A sequence is smaller than another in lexicographic order if the first element on which they differ is smaller in the first one).

Sample Input

2 10 13 30 11 22 04 30 12 31 30 0

Sample Output

2: 0 0Impossible4: 1 3 3 1

Hint

题意:
You can aim at one of the trees and shoot; 
your bullets are capable of going through the branches and killing the monkey instantly if it happens to be in that tree.
If it isn't, the monkey takes advantage of the time it takes you to reload and takes a leap into a neighbouring tree without you noticing.
It never stays in the same place after a shot.
对准一棵树射击,如果有猴子在这棵树上则射击成功,否则猴子将会转移到另一棵树上(并且一定会转移)
You would like to find out whether there is an strategy that allows you to capture the monkey for sure, irrespective of its initial location and subsequent jumps.
If so, you need to determine the shortest sequence of shots guaranteeing this. 
在保证射击成功的前提下,找一个最短的射击序列(不管猴子的初始位置和随后跳跃的位置)(同等长度输出字典序最小的)

思路:(看了大佬们的题解)
状压+最短路

  1.点数n只有21明显可以状压。用状态st表示当前猴子可能的位置,初始状态为(1<<n)-1。很明显,必然打中的状态就是1<<k(1<=k<=n)的时候,猴子死亡的情况也就可       以表示为状态0.

  2.考虑每一次攻击,每次攻击的点肯定是那些当前可能有猴子存在的点,再考虑每次攻击状态的转移:对于状态st,攻击的位置i,则i位置置0,而其它为1的位置清零后,其邻      接位置置1

  3.所以问题就转化为由状态(1<<n)-1到0的最短路径
  4.为了同时保证字典序最小,可以在每次枚举攻击位置的时候从小到大枚举

     
#include<iostream>#include<vector>#include<queue>using namespace std;const int N=22;const int Max=1<<N;int vis[Max],pre[Max],shoot[Max];int n,m;vector<int> ans,p[N];bool bfs(int sum){vis[sum]=1;queue<int> q;q.push(sum);while(!q.empty()){int st=q.front();q.pop();if(!st) return true;for(int i=0;i<n;i++){int next=0;for(int j=0;j<n;j++)if(i!=j&&(st&(1<<j)))for(int k=0;k<p[j].size();k++)next|=(1<<p[j][k]);if(vis[next]) continue;vis[next]=1;pre[next]=st;shoot[next]=i;q.push(next);}}return false;}int main(){while(cin>>n>>m,n+m){int sum=(1<<n)-1;for(int i=0;i<=sum;i++) vis[i]=0;for(int i=0;i<n;i++)    p[i].clear();for(int a,b,i=0;i<m;i++){cin>>a>>b;p[a].push_back(b);p[b].push_back(a);    }  if(bfs(sum)){ans.clear();int now=0;while(now!=sum){ans.push_back(shoot[now]);now=pre[now];}cout<<ans.size()<<":";for(int i=ans.size()-1;i>=0;i--) cout<<" "<<ans[i];}else cout<<"Impossible";cout<<endl;}}


0 0
原创粉丝点击