終于做到的C4,然而基礎的不牢固致使C4做的這么艱難。基本上攙扶著做了這節(jié)的題,搜索剪枝啊,確實是門學問,而且搜索經常寫做,得不出結果,郁悶。

Beef McNuggets (nuggets)
動態(tài)規(guī)劃,需要做一下預處理,找兩個最小的互質的數之積作為搜索上界。如果a,b互質,則ax+by=有>=a*b的整數解,這樣就很快了。

Fence Rails (fence8)
參考了Qinz牛的blog,需要很多剪枝,這里用到了一個叫dfsid的迭代加深搜索算法,大意是dfs過程中如果求最短,就由淺至深增加深度直至找到解,此題是由深至淺,如果找到解就輸出,否則深度減少。
dfsid偽代碼如下:

DFSID
procedure dfs(depth:longint);
 begin
  if 要剪枝 then exit;
  if 可行 then Print;
  if Depth<MaxDepth then dfs(depth+1);
 end;

procedure Iterative_Deepening;
 begin
  MaxDepth:=0;
  while true do
   begin
    inc(MaxDepth);
    dfs(1);
   end;
 end;

Fence Loops (fence6)
這題求最小環(huán),我圖論學的少,所以就搜索著做的,搜索的時候是兩個方向,建立模型的時候有點兒技巧,沒有什么剪枝就能過。
另外可以用dijkstra做,對每條邊先去掉,求最短路徑,再加上這條邊,取最小值。
我覺得這個代碼不錯,把邊轉化成點做的,程序很簡潔,分享代碼:

Dijkstra
Dijkstra
#include <stdio.h>
#define MAX 30000
 
int n;
int len[101];
int map[2][101][8];
 
void pre(){
    int i,j,k;
    scanf("%d",&n);
    for(i=0;i<n;i++){
        scanf("%d",&j);
        scanf("%d",&len[j]);
        scanf("%d%d",&map[0][j][0],&map[1][j][0]);
        for(k=1;k<=map[0][j][0];k++)scanf("%d",&map[0][j][k]);
        for(k=1;k<=map[1][j][0];k++)scanf("%d",&map[1][j][k]);
    }
}
 
int dis[101];
int isi[101];
int bef[101];
 
int dijkstra(int z){
    int i,j,k;
    for(i=1;i<=n;i++){dis[i]=MAX;isi[i]=0;}
    for(i=1;i<=map[0][z][0];i++){bef[map[0][z][i]]=z;dis[map[0][z][i]]=len[z];}
    while(1){
        j=0;k=MAX;
        for(i=1;i<=n;i++)
            if(dis[i]<k && isi[i]==0){
                j=i;
                k=dis[i];
            }
        if(j==0)break;
        if(j==z)return dis[z];
        isi[j]=1;
        for(i=1;i<=map[0][j][0];i++)
            if(map[0][j][i]==bef[j])break;
        if(i==map[0][j][0]+1)k=0;
        else k=1;
        for(i=1;i<=map[k][j][0];i++){
            if(dis[map[k][j][i]]>dis[j]+len[j]){
                dis[map[k][j][i]]=dis[j]+len[j];
                bef[map[k][j][i]]=j;
            }
        }
    }
    return MAX;
}
 
main(){
    freopen("fence6.in","r",stdin);
    freopen("fence6.out","w",stdout);
    int i,j=MAX,k;
    pre();
    for(i=1;i<=n;i++){
        k=dijkstra(i);
        if(k<j)j=k;
    }
    printf("%d\n",j);
    return 0;
}

Cryptcowgraphy (cryptcow)
又是搜索,這個就是看了別人的解題報告。
剪枝方案:
1.如果C O W出現的順序不是C在最前面,W在最后面,剪掉。
2.如果除去C O W后字符串字母和原字符串不符,剪掉。
3.如果 C O W不是成對出現,剪掉
4.用ELFhash函數為出現的字符串判重。

ELFhash
int hasher(char *k){
 unsigned long h=0,g;
 while(*k){
  h=(h<<4)+*k++;
  g=h &0xf0000000l; //7個0;
  if(g) h^=g>>24;
  h&=~g;
 }
 return h;
}