POJ PKU 3028 Nordic 2006

第一次寫C++,手生導致此題耗了兩個晚上總計6個小時(好在是自己做出來的)(391ms)

題意:

有n個人,站成一個圈。每個人開槍擊中別人的概率是固定的(設數組P[i]表示第i個人的命中率),從第一個人開始輪流開槍,求每個人的生還的概率是多少?(假設每人都以最有利自己的方式選擇射擊對象,並且當有多個目標都一樣好時,隨機選擇其中一個(即m個好對象時,每個對象被他選中的概率爲1/m)。並且,每輪都必須射擊,雖然故意放棄射擊機會可能增大存活的概率)。

不許自殺。

這個題其實是一個環狀DP方程應該很好想

F[i,j,s]表示s狀態下,輪到第j個人射擊時,第i個人存活概率(i,j爲原題的第i個和第j個)s爲二進制表示的集合

F[i,j,s]=(sigma(F[i,next(j,k,s),s^pow[k-1]]/sigma{k的個數})*P[j]+(1-P[j])*F[i,next(j,s).s]

首先在確定的s下

令A[j]=F[i,j,s] A[j+1]=F[i,next(j,s),s] A[j+2]=F[i,next(next(j,s),s),s]  .......

b[j]=(sigma(F[i,next(j,k,s),s^pow[k-1]]/sigma{k的個數})*P[j]

Q[j]=1-P[j]

b[j+1],Q[j+1]所表示的類似於A[j+1]

那麼按方程展開有A[j]=b[j]+Q[j]a[j+1]=b[j]+Q[j]b[j+1]+Q[j]Q[j+1]a[j+2]=.....................

最後由於有環,展開之後就可以回到A[j]了,且係數爲Q[1]到Q[m]的累乘,然後移項相減相除,

Final  A[j]=(b[j]+Q[j]b[j+1]+Q[j]Q[j+1]b[j+2]+.......+Q[j]*Q[j+1]*...*Q[j-1]b[j-1])/(1-Q[1]至Q[m]的累乘)

而b[j]的係數也可以找到規律

算法就出來了

STEP 1

枚舉S(從1到pow[n]-1)

     {

     STEP 2

    計算每個人的決策;

      STEP 3

     枚舉 i{i in s}

         {STEP 4

         計算 i 下的 b[j];

          STEP 5

         枚舉j (j in s)計算F[i,j,s];

          }

     }

複雜度O((n^3)*(2^n))

注意STEP 5有兩重循環

每個人的答案就是F[i,1,pow[n]-1]

一下是代碼

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#define zero(a) ((fabs(a)<eps))/*注意是Fabs,不是abs*/
#define equal(a,b) (zero(((a)-(b))))
const int ppo[]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192};
const double eps=1e-12;
int plan[15][15];
double p[15],b[15];
double f[14][14][8192];
int head;
int que[15];
int next[15][8192];
void prepare()
{
  memset(p,0,sizeof(p));
}
void calcplan(int now,int state)/*即時計算S下now的決策,注意可能有多個選擇,但沒有自己!(不許自殺)*/
{
  double maxt=0;
  for(int l=1;l<=head;l++)
    if (que[l]!=now)
      {
	int kill=que[l];
	int k=next[now][state];
	if (k==kill) k=next[k][state];
	double com=f[now][k][state^ppo[kill-1]];
	if (equal(com,maxt))
	      {
		plan[now][0]++;
		plan[now][plan[now][0]]=kill;
	      }
	else
	  if (com>maxt)
		{
		  plan[now][0]=1;
		  maxt=com;
		  plan[now][1]=kill;
		}
      }
}
void ready()/*計算每個S下下個人是誰,存入next數組*/
{
  for (int state=1;state<ppo[13];state++)
    {
      head=0;
      memset(que,0,sizeof(que));
      int stmp=state;
      for(int i=1;i<=13;i++)
	    {
	      if (stmp & 1==1)
		{
		  head++;
		  que[head]=i;
		  next[que[head-1]][state]=que[head];
		};
	      stmp=stmp>>1;
	    }
      next[que[head]][state]=que[1];
      next[0][state]=0;
    }
}
int main()
{
  int task=0;
  ready();
  freopen("poj3028.in","r",stdin);
  freopen("poj3028.out","w",stdout);
  scanf("%d",&task);
  for(;task>0;task--)
    {
      prepare;
      int n;
      int i;
      scanf("%d",&n);
      for(i=1;i<=n;i++)
	{
	  scanf("%lf",&p[i]);
	  p[i]/=100;
	}
      int state;
      for(state=1;state<ppo[n];state++)
	{
	  memset(plan,0,sizeof(plan));
	  memset(que,0,sizeof(que));
	  head=0;
	  memset(b,0,sizeof(b));
	  int stmp=state;
	  int j=0;
	  double tot=1;
	  for(i=1;i<=n;i++)
	    {
	      if (stmp & 1==1)
		{
		  head++;
		  que[head]=i;
		  tot=tot*(1-p[i]);
		};
	      stmp=stmp>>1;
	    }
	  if (head==1)
	    {
	      f[que[1]][que[1]][state]=1;
	      continue;
	    }
	    /*特殊處理1個人的情況!*/
	  tot=1-tot;
	  for(i=1;i<=head;i++)
	    calcplan(que[i],state);/*記錄決策計劃中無自己*/    
	  for(int p1=1;p1<=head;p1++)
	    {
	      i=que[p1];
	      for(int p2=1;p2<=head;p2++)/*計算i下的B[j]*/
		{
		  j=que[p2];
		  double sum=0;
		  for(int p3=1;p3<=plan[j][0];p3++)
		    {
		      int k=next[j][state];
		      if (k==plan[j][p3]) k=next[k][state];
		      sum+=f[i][k][state^ppo[plan[j][p3]-1]];
		    }
		  sum/=plan[j][0];
		  b[p2]=sum*p[j];
		}
	      for(int p2=1;p2<=head;p2++)/*計算F[i,j,s]*/
		{
		  j=que[p2];
		  double sum=0;
		  double times=1;
		  for(int p3=p2;p3<=head;p3++)
		    {
		      sum+=b[p3]*times;
		      times*=(1-p[que[p3]]);
		    }
		  for(int p3=1;p3<p2;p3++)
		    {
		      sum+=b[p3]*times;
		      times*=(1-p[que[p3]]);
		    }
		  f[i][j][state]=sum/tot;
		}
	    }
	}
      for (int i=1;i<=n;i++)
	{
	  printf("%.2f ",f[i][1][ppo[n]-1]*100.0);
	}
      printf("\n");
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章