zoukankan      html  css  js  c++  java
  • SPOJ 423 Assignments 状态DP

    这个题目搁置了这么久,终于搞完了。

    给n个人分配n个课程,已经告诉了你n个人对哪几门感兴趣,问最多有多少种分配方式

    我刚开始都没找到这怎么还可以状态dp,哪来的状态转移,想用暴力DFS,果断TLE的妥妥的。

    后来给殷犇发了这个题目,他还说你刷个这水题还刷得这包子劲,这题目就是后一行的状态由前一行得到,枚举当前这一行分配的状态,如果可行,就从后面的状态加过来

    由于状态只是从上一行转移过来,所以可以用滚动数组,用p表示当前,则!p就为上一行的,每次结束再把p置反即可。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define ll long long
    using namespace std;
    int n;
    int sta[22];
    ll dp[2][1<<21];
    int calc[22][1<<21],cnt[22];
    void init()
    {
        memset(calc,0,sizeof calc);
        memset(cnt,0,sizeof cnt);
        for (int i=0;i<(1<<21);i++) //这里把只有一门课 两门。。。N门课全部用一个数组存起来,calc[i][]就代表有i个课程的状态,因为不止一种 所以开了两维。
        {
            int tmp=0;
            for (int j=i;j;j>>=1)
            {
                if (j&1)
                    tmp++;
            }
            calc[tmp][cnt[tmp]++]=i;
        }
    }
    int main()
    {
        int t,a;
        scanf("%d",&t);
        init();
        while (t--)
        {
          scanf("%d",&n);
          for (int i=0;i<n;i++)
          {
              sta[i]=0;
              for (int j=0;j<n;j++)
              {
                  scanf("%d",&a);
                  if (a==1)
                  {
                      sta[i]+=1<<j;//存入学生感兴趣的课程的状态。
                  }
              }
          }
    
          int p=0,all=(1<<n)-1;
          //memset(dp,0,sizeof dp);
          dp[1][0]=1;
          for (int i=0;i<n;i++)//从第0个人循环到第n-1个人
          {
              for (int k=0,s=calc[i+1][k];k<cnt[i+1]&&calc[i+1][k]<=all;s=calc[i+1][++k])//当前是第i号人 则状态必定是calc[i+1][]的状态,比如第三个人就只分配三个课程即可,一旦可行 就从分配了两个课程的状态那里转移过来。
              {
                  dp[p][s]=0;
                  for (int j=0;j<n;j++)//逐个试探第j号课程是否可以
                  {
                      //dp[p][k]=0;
                     if (((1<<j)&sta[i])==0) continue;
                      if ((1<<j)&s)
                      {
                          //dp[p][k]+=1;
    
                           dp[p][s]+=dp[p^1][(1<<j)^s];//一旦该状态可以,则从上一次的不含新分配的课程的那里转移过来
                      }
    
                     //else
                      //  dp[p][k]+=dp[p^1][k];
                  }
              }
              p^=1;
          }
          printf("%lld
    ",dp[p^1][all]);
        }
        return 0;
    }
  • 相关阅读:
    封装aixos拦截器
    vue路由传参的三种基本方式
    vue里的路由钩子
    箭头函数特点
    webstorm激活码
    vue-cli2使用less
    vue-cli2使用rem适配
    XfZGkvBaeh
    python解析excel中图片+提取图片
    python解析谷歌在线表格链接,转化为数组形式,图片转化为链接
  • 原文地址:https://www.cnblogs.com/kkrisen/p/3604699.html
Copyright © 2011-2022 走看看