SPOJ 196 Musketeers(JAVA版)

来源:互联网 发布:如何重启linux服务器 编辑:程序博客网 时间:2024/05/19 02:45

SPOJ 196 Musketeers

題目大意:有n个人要进行n-1场决斗,最后只能有一个人存活,决斗可以从这n个人任意一个开始,但是只有相邻的两个人能进行决斗,问最后哪些人有可能活下来,输出人数,并把他们的序号从小到大输出。

思路如下:因为这n个人排成一个圈,任意相邻两个人可以进行决斗(最后一个人可以和第一个人决斗,一个圈),于是先用n+1长度的数组构造一个“人链”,数组的开头和结尾是同一个人比如:有5个人,先从第一个人开始看,1站排头,即a0,a1,a2,a3,a4,a5分别是1,2,3,4,5,1。每有一个人死亡,那个人就退场,直到最后,如果能够首尾相邻那就表示那个人能够获胜。考虑获胜前最后一个状态便可。即第k个人,可以被排头的人打败或者被排尾的人打败,并且最后会剩下三个人(排头,k,排尾)。如此排头(即排尾)的这个人就能获胜,这就知道是dp了。
dp[i][j]表示第 i 人与第 j 人能否相遇,能为1,否为0;a[i]表示人链中排第 i 的人;f[i][j]用来记录题目中的数组。

动态转移方程:dp[i][j]=(((f[a[i]][a[k]] || f[a[j]][a[k]]) && dp[i][k] && dp[k][j])?1:0);(i<k<j)

这里附上两份代码,因为第一次做是用递归(记忆化搜索)做的,后来想想,因为习惯,改成了循环。

AC代码:(循环)

import java.util.Scanner;public class Main{static Scanner scan=new Scanner(System.in);public static void main(String[] args){int t=scan.nextInt();while(t-->0){int n=scan.nextInt();int f[][]=new int[n+1][n+1];String str=scan.nextLine();for(int i=1;i<n+1;i++){str=scan.nextLine();for(int j=1;j<n+1;j++)f[i][j]=str.charAt(j-1)-48;}int dp[][]=new int[n+1][n+1];int a[]=new int[n+1];int ans[]=new int[n+1];//这个数组用来记录获胜的人int cas=0;for(int len=1;len<n+1;len++)//len表示第len个人在排头(考察他是否能胜出){int meet=len;for(int k=0;k<n+1;k++)//这个循环构造人链{if(meet<=n)a[k]=meet;elsea[k]=meet-n;meet++;}for(int i=1;i<n+1;i++)for(int j=0;j+i<n+1;j++){if(j+1==j+i)//如果左右相邻,直接就是能两人能相遇dp[j][j+i]=1;else{for(int k=j+1;k<j+i;k++)//找人if((f[a[j]][a[k]]==1 || f[a[j+i]][a[k]]==1) && dp[j][k]==1 && dp[k][j+i]==1){dp[j][j+i]=1;break;}//满足条件就赋1,然后breakelse dp[j][j+i]=0;//因为这个数组要用很多次,所以找不到还是赋0}}if(dp[0][n]==1)//相遇了ans[cas++]=len;//记}System.out.println(cas);for(int i=0;i<cas;i++)System.out.println(ans[i]);}}}
AC代码:(递归)

import java.util.Scanner;public class Main//标注的地方是跟循环不一样的地方{static Scanner scan=new Scanner(System.in);public static int winner(int L, int R, int[] a, int[][] dp, int[][] f){if(dp[L][R]!=-1)//记忆化搜索,看看是否检查过return dp[L][R];if(L+1==R)return dp[L][R]=1;int flag=0;for(int i=L+1;i<R;i++)if((f[a[L]][a[i]]==1 || f[a[R]][a[i]]==1) && winner(L, i, a, dp, f)==1 && winner(i, R, a, dp, f)==1){flag=1;break;}return dp[L][R]=flag;}public static void main(String[] args){int t=scan.nextInt();while(t-->0){int n=scan.nextInt();int f[][]=new int[n+1][n+1];String str=scan.nextLine();for(int i=1;i<n+1;i++){str=scan.nextLine();for(int j=1;j<n+1;j++)f[i][j]=str.charAt(j-1)-48;}int dp[][]=new int[n+1][n+1];int a[]=new int[n+1];int ans[]=new int[n+1];int cas=0;for(int i=1;i<n+1;i++){for(int x=0;x<n+1;x++)for(int y=0;y<n+1;y++)dp[x][y]=-1;//初始化,每进一次循环初始化一次,全部为-1,因为未检查(这个地方在记忆化搜索起作用)int meet=i;//构造人链for(int j=0;j<n+1;j++){if(meet<=n)a[j]=meet;elsea[j]=meet-n;meet++;}if(winner(0, n, a, dp, f)==1)//0与n能否相遇,即首尾ans[cas++]=i;}System.out.println(cas);for(int i=0;i<cas;i++)System.out.println(ans[i]);}}}

0 0
原创粉丝点击