【日记】6.14

  几天做了几道状态压缩的题目,然后下午考试竟然真的让我碰到了、

①第一道题,是一个字母树的问题,我没有写,因为在插入后的查找构建N次字母树就超时了,但是我写了个最简单的搜索的,目测能过50%但是提交的时候晚了1分钟……于是就没有这道题的成绩了,50分啊( ⊙ o ⊙ )

最后知道,只要把读入的数据线排序,在查询的时候插入就好了……这么简单竟然没有想到。

 

②刚看的状态压缩,就遇到这种题让我情何以堪,果断状态压缩搞之,把每一列的状态压缩成一个数字,那么就应该是0~15,不难得到状态转移方程:

f[i+1][j]=∑f[i][k]  f[i][j]表示当前第i行状态为j的方法数,枚举每一行然后dfs就可以完成状态转移了,这个时间复杂度应该是O(K*N)的,k是个常数,具体不知道,因为dfs的时间复杂度不怎么会算。

明显是只能拿70%的,结果确实只有70分,但是我们可以知道,这是一个递推的式子,就可以试着用矩阵乘法优化,那么构造一个矩阵A,为16*16,对角线为1,其余为0,连乘N次后再和f[1]这行相乘,就能得到f[N+1],最后的答案就是f[n+1][0],而矩阵的N次方很明显可以用矩阵乘法优化。

背包问题【状态压缩】
 1 /**
 2 *Prob    : baga
 3 *Data    : 2012-6-14
 4 *Sol    : 状态压缩递推
 5 *Author : Zhou Hang
 6 */
 7 
 8 #include <cstdio>
 9 #include <cstring>
10 #include <algorithm>
11 
12 #define MaxT 16
13 #define oo 997
14 #define MaxN 1000000
15 
16 
17 using namespace std;
18 
19 int n,i,j;
20 int f[MaxN][MaxT];
21 
22 //k表示在第k个格子,s表示当前铺砖状态,news表示下一层被上一层所影响的状态
23 void Dfs(int k,int s,int news)
24 {
25     if (k==4)
26     {
27         f[i+1][news]=(f[i+1][news]+f[i][j])%oo;
28         return;
29     }
30     //当前位置已经被铺就跳下一格
31     if ( s&(1<<k) ) 
32         Dfs(k+1,s,news);
33     else {
34         //竖铺
35         Dfs(k+1,s|(1<<k),news|(1<<k));
36         //横铺
37         if ( ((s&(1<<(k+1)))==0 ) && (k+1<4) )
38             Dfs(k+2,((s|(1<<k)))|((1<<(k+1)) ),news);
39     }    
40 }
41 
42 int main()
43 {
44     freopen("baga.in","r",stdin);
45     freopen("baga.out","w",stdout);
46     
47     scanf("%d",&n);
48 
49     f[1][0]=1;
50     for (i=1; i<=n; i++)
51     {
52      for (j=0; j<=15; j++)
53         if (f[i][j]>0) Dfs(0,j,0);
54     }
55 
56     printf("%d\n",f[n+1][0]%oo);
57 
58     fclose(stdin); fclose(stdout);
59     return 0;
60 }

 

③很明显的1D1D动态规划,先将工作的难度排序,那么安排给每个人的工作必须是连续的,这样才能保证总酬劳最小

f[i]=min(f[j]+w[j+1,i])  相当于枚举最后一个人做的什么工作,这个算法的时间复杂度是O(n^2)的,10000的数据勉强能过

其实进一步想,这个递推公式中的w其实是满足凸性的(具体看四边形不等式),很简单就可以证明,那么就告诉了我们,这个决策是单调的,那么f[i]的决策可以从f[i-1]的最优决策开始向后枚举,或者用斜率优化都基本上可以优化到O(n)级别的。但是我貌似优化错了……最裸的也写错了,虽然分段了还是没有拿到分数。

决策单调性
 1 /**
 2 *Prob    : dividea
 3 *Data    : 2012-6-14
 4 *Sol    : 动归+决策单调性
 5 */
 6 
 7 #include<iostream>
 8 #include<stdio.h>
 9 #include<cstring>
10 #include<algorithm>
11 using namespace std;
12 
13 int n,K,C;
14 long long f[1000005];
15 long long a[1000005];
16 
17 int cmp(const void *a,const void *b)
18 {
19     if(*(long long *)a>*(long long *)b) return 1;
20     return -1;
21 }
22 
23 void work()
24 {
25      int i,j,last,noww;
26      memset(f,0x7f,sizeof(f));
27      f[0]=0;
28      last=0;
29      for(i=K; i<=n; i++)
30      {
31                  noww=last;
32                  for(j=last; j<=i-K; j++)
33                  if(f[i]>=f[j]+(a[i]-a[j+1])*(a[i]-a[j+1])+C)
34                  {
35                       f[i]=f[j]+(a[i]-a[j+1])*(a[i]-a[j+1])+C;
36                       noww=j;                                                                                  
37                  }
38                  last=noww;
39      }
40 }
41 
42 void print()
43 {
44      
45 }
46 
47 int main()
48 {
49     
50      freopen("dividea.in","r",stdin);
51      freopen("dividea.out","w",stdout);
52 
53      scanf("%d%d%d\n",&n,&K,&C);
54      int i;
55      for(i=1; i<=n; i++)
56      scanf("%d",&a[i]);
57      qsort(a+1,n,sizeof(a[1]),cmp);
58 
59      work();
60 
61      printf("%I64d\n",f[n]);
62 
63      fclose(stdin); fclose(stdout);
64      return 0;
65 }


 

这次的考试失误太多了,比如第一题没有交上去,为了提醒自己就没有去补交了,还有最后一题的优化也写错了,理论上是最裸的就过了,事实也是如此。

理论上这如果真是考试的话,预计得分应该是220左右。需要复习下矩阵乘法了,这也是下个星期的目标之一。

posted @ 2012-06-15 09:19  守護N1身边  阅读(111)  评论(0编辑  收藏  举报