2013金山西居挑戰賽初賽1—轉自blog.csdn.net/asdfgh0308/

剛水了這場比賽:2013金山西山居創意遊戲程序挑戰賽——初賽(1)。
簡要題解如下:
1001 魔法串:
問第二個串能不能變成第一個串。
顯然的DP問題。dp[i][j]表示第二串前j個變成第一串前i個是否可行。
轉移就是
if (dp[i][j-1]==1) dp[i][j]=1;
if (dp[i-1][j-1]==1&&g[t[j]][s[i]]==1){dp[i][j]=1;}
g[a][b]爲1表示a字符能變成b字符。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define NN 1010

int cas,tcas,i,g[300][300],j,l1,l2,dp[NN][NN],m;
char s[NN],t[NN],sa[50],sb[50];

int main(){
    scanf("%d",&tcas);
    for(cas=1;cas<=tcas;++cas){
        scanf("%s%s",s+1,t+1);
        s[0]=t[0]='*';
        scanf("%d",&m);
        memset(g,0,sizeof(g));
        for(i='a';i<='z';++i){g[i][i]=1;}
        for(i=1;i<=m;++i){
            scanf("%s%s",sa,sb);
            g[sa[0]][sb[0]]=1;
        }


        memset(dp,0,sizeof(dp));
        l1=strlen(s)-1;l2=strlen(t)-1;
        for(i=0;i<=l2;++i) dp[0][i]=1;
        for(i=1;i<=l1;++i){
            for(j=i;j<=l2;++j){

                if (dp[i][j-1]==1){
                    dp[i][j]=1;
                }
                if (dp[i-1][j-1]==1&&g[t[j]][s[i]]==1){
                    dp[i][j]=1;
                }
            }
        }
        printf("Case #%d: ",cas);
        printf("%s\n",dp[l1][l2]?"happy":"unhappy");
    }
    return 0;
}
View Code

1002 比賽難度:
人品不錯,前幾天剛在中南月賽中做了一個類似的題目:求第m小的三個素數相乘所得的數。(想想怎麼做?)

顯然,m很小,很容易想到構造的方式。問題是怎麼構造出比較小的可能的狀態。
用優先隊列類似寬搜的方式,每次加入最有可能的幾個狀態。然後在隊列中取最小的狀態繼續搜索。

將題目按照難度排序。
這題狀態可以記錄爲兩個值,a:當前所取的總難度和,b:最後取的一道題的題號。
那麼從這個狀態拓展的下一個最有可能的狀態就是
1:去掉第b道題,取第b+1道題;
2:取現在狀態所取的所有題加上第b+1道題。

這樣搜索下去就能不重複不遺漏地取到所有的狀態。而每次取出一個狀態最多隻會加入兩個狀態,這樣時間空間都是0(M)。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<map>
#include<algorithm>
using namespace std;
#define NN 20100

struct node{
    int a,b;
    bool operator <(const node &y)const{
        if (a==y.a) return b>y.b;
        else return a>y.a;
    }
}tn,un;

priority_queue<node> q;
int v[NN];

int main(){
    int tcas,cas,n,m,i,a,b,tot,ans;
    scanf("%d",&tcas);
    for(cas=1;cas<=tcas;++cas){
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;++i){
            scanf("%d",&v[i]);
        }
        sort(v+1,v+n+1);
        while(!q.empty()) q.pop();
        tn.a=v[1];tn.b=1;
        q.push(tn);
        tot=0;
        while(!q.empty()){
            un=q.top();q.pop();
            tot++;
            //printf("%d %d\n",un.a,un.b);
            if (tot>=m) {ans=un.a;break;}
            a=un.a;b=un.b;
            if (b<n){
            tn.a=a-v[b]+v[b+1];tn.b=b+1;
            q.push(tn);
            tn.a=a+v[b+1];tn.b=b+1;
            q.push(tn);
            }

        }
        printf("Case #%d: %d\n",cas,ans);
    }
    return 0;
}
View Code

1003 CD操作:
其實CD這個命令可以直接輸入目標文件夾的絕對路徑,這樣一次就夠了我會亂說?

這題的cd只能返回上一層,而向下可以一次到達。
顯然的LCA問題,求出兩個目錄的最小公共祖先目錄,一直向上找到這個目錄爲止,再一次(或是0次)走到目標目錄即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
using namespace std;
#define NN 100005
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)

int mr[NN*2][18],first[NN],next[NN],w[NN],R[NN];
int tote,totn;
int i,deg[NN],a,b,cas,n,root,ans;

map<string,int> mp;
char ts1[50],ts2[50];
string str1,str2;

struct node{
       int o,dep;
}aa[NN*2];

void lcadfs(int now,int dep){
     aa[++totn].o=now;
     aa[totn].dep=dep;
     int e;
     for(e=first[now];e!=-1;e=next[e]){
        lcadfs(w[e],dep+1);
        aa[++totn].o=now;
        aa[totn].dep=dep;
     }
}

void rmqinit(){
     int m=-1,k=totn;
     while(k) {m++;k>>=1;}
     int i,j;
     for(i=1;i<=totn;i++) {mr[i][0]=i;}//mr記錄最小值位置
     for(i=1;i<=m;i++){
         for(j=1;j<=totn;j++){
             mr[j][i]=mr[j][i-1];
             if (j+(1<<(i-1))<=totn) {
                   if (aa[mr[j][i]].dep>aa[mr[j+(1<<(i-1))][i-1]].dep){
                       mr[j][i]=mr[j+(1<<(i-1))][i-1];
                   }
             }
         }
     }
}

int rmqmin(int l,int r){
    int m=-1,k=r+1-l;
    while(k) {k>>=1;m++;}
    if (aa[mr[l][m]].dep<aa[mr[r+1-(1<<m)][m]].dep){
        return mr[l][m];
    }
    else return mr[r+1-(1<<m)][m];
}




int main(){
    int m,tots;
    scanf("%d",&cas);
    while(cas--){
       mp.clear();
       scanf("%d%d",&n,&m);
       for(i=1;i<=n;i++){first[i]=-1;deg[i]=0;}
       tote=0;
       tots=0;
       for(i=1;i<=n-1;i++){
           scanf("%s%s",ts1,ts2);
           str1=ts1;str2=ts2;
           if (mp[str1]==0) mp[str1]=++tots;
           if (mp[str2]==0) mp[str2]=++tots;
           b=mp[str1];a=mp[str2];
           tote++;
           next[tote]=first[a];
           first[a]=tote;
           w[tote]=b;
           deg[b]++;
       }
       for(i=1;i<=n;i++)   if (deg[i]==0) {root=i;break;}
       totn=0;
       lcadfs(root,0);
       memset(R,0,sizeof(R));

       for(i=1;i<=totn;i++){
           if (!R[aa[i].o]) R[aa[i].o]=i;
       }

       rmqinit();
       int tmp;
       for(i=1;i<=m;++i){
            scanf("%s%s",ts1,ts2);
            str1=ts1;str2=ts2;
            a=mp[str1];b=mp[str2];
            if (R[a]>=R[b]) tmp=rmqmin(R[b],R[a]);
            else tmp=rmqmin(R[a],R[b]);
            ans=aa[R[a]].dep-aa[tmp].dep;
            if (aa[tmp].o!=b) ans+=1;
            printf("%d\n",ans);
        }
    }
    return 0;
}
View Code

 

 

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