2013金山西山居创意游戏程序挑战赛——复赛(1) HDU 4557 非诚勿扰 HDU 4558 剑侠情缘 HDU 4559 涂色游戏 HDU 4560 我是歌手

今天的比赛。。。。。速度还是慢了。。。

无缘无故错误提交好多次。。哭了。。。。

 

比较简单:

A题:HDU 4557 

非诚勿扰

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4557

 

暴力胡搞,水题:

//============================================================================

// Name        : A.cpp

// Author      : 

// Version     :

// Copyright   : Your copyright notice

// Description : Hello World in C++, Ansi-style

//============================================================================



#include <iostream>

#include <stdio.h>

#include <string.h>

#include <algorithm>

#include <queue>

#include <vector>

#include <map>

#include <set>

#include <string>

#include <math.h>

using namespace std;

const int MAXN=1010;

char str[MAXN][100];

int a[MAXN];

bool used[MAXN];





int main()

{

//    freopen("in.txt","r",stdin);

//    freopen("out.txt","w",stdout);

    int T;

    int n;

    int top;

    scanf("%d",&T);

    int iCase=0;

    while(T--)

    {

        iCase++;

        printf("Case #%d:\n",iCase);

        scanf("%d",&n);

        char op[20];

        memset(used,false,sizeof(used));

        int num=0;

        top=0;

        while(n--)

        {

            scanf("%s",&op);

            if(op[0]=='A')

            {

                scanf("%s%d",&str[top],&a[top]);

                top++;

                num++;

                printf("%d\n",num);

            }

            else

            {

                int tmp;

                scanf("%d",&tmp);

                int k=-1;

                for(int i=0;i<top;i++)

                    if(!used[i]&&a[i]>=tmp)

                        if(k==-1||(a[i]<a[k]))

                        {

                            k=i;

                        }

                if(k==-1)printf("WAIT...\n");

                else

                {

                    printf("%s\n",str[k]);

                    used[k]=true;

                    num--;

                }

            }

        }

    }



    return 0;

}
A

 

 

B题:HDU 4558 

剑侠情缘

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4558

 

DP

一开始状态想错了。。只要记录差值就可以的

 

dp[i][j][x]表示在(i,j)这个点,差值为x

转移的时候把差值取相反数就实现轮流了

dp[i][j][x]表示(i,j)出发。人和剑的能量的差值为x.可以得到的相反数

那么状态转移的时候,首先x+=这个点的值。。如果这个时候x==0表示想到了,那么dp[i][j][x]++

然后往下和往右转移。下一步是更新剑了。所以对x取相反数

 

//============================================================================

// Name        : B.cpp

// Author      : 

// Version     :

// Copyright   : Your copyright notice

// Description : Hello World in C++, Ansi-style

//============================================================================



#include <iostream>

#include <stdio.h>

#include <string.h>

#include <algorithm>

#include <queue>

#include <vector>

#include <map>

#include <set>

#include <string>

#include <math.h>

using namespace std;

const int MAXN=500;

char str[MAXN][MAXN];

const int MOD=1e9+7;

int dp[MAXN][MAXN][11];



int main()

{

//    freopen("in.txt","r",stdin);

//    freopen("out.txt","w",stdout);

    int T;

    int n,m;

    scanf("%d",&T);

    int iCase=0;

    while(T--)

    {

        iCase++;

        printf("Case %d: ",iCase);

        scanf("%d%d",&n,&m);

        for(int i=0;i<n;i++)scanf("%s",str[i]);

        int ans=0;

        memset(dp,0,sizeof(dp));

        for(int i=n-1;i>=0;i--)

        {

            for(int j=m-1;j>=0;j--)

            {

                for(int x=0;x<11;x++)

                    {

                        int tmp=x+(str[i][j]-'0');

                        tmp=(tmp)%11;

                        int tmp2=(11-tmp)%11;

                        if(i<n-1)

                        {

                            dp[i][j][x]+=dp[i+1][j][tmp2];

                        }

                        dp[i][j][x]%=MOD;

                        if(j<m-1)dp[i][j][x]+=dp[i][j+1][tmp2];

                        dp[i][j][x]%=MOD;

                        if(tmp==0)

                        {

                            dp[i][j][x]++;

                            dp[i][j][x]%=MOD;

                        }

                        if(x==0)

                        {

                            ans+=dp[i][j][x];

                            ans%=MOD;

                        }

                    }

            }

        }

        printf("%d\n",ans);

    }

    return 0;

}
B

 

 

C:HDU 4559 

涂色游戏

博弈题:

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4559

SG函数计算。

SG函数很高深。。。

想了好久才会。

其实1*1的点sg值就是1

sg[i]表示2*i 的sg值。

sg[i]求解就是普通的SG函数了。

 

然后进行分段做。

 

分段;

//============================================================================

// Name        : C.cpp

// Author      : 

// Version     :

// Copyright   : Your copyright notice

// Description : Hello World in C++, Ansi-style

//============================================================================

#include <iostream>

#include <stdio.h>

#include <string.h>

#include <algorithm>

#include <queue>

#include <vector>

#include <map>

#include <set>

#include <string>

#include <math.h>

using namespace std;

const int MAXN=5000;

int sg[MAXN];

bool vis[MAXN];

int mex(int x)

{

    if(sg[x]!=-1)return sg[x];

    memset(vis,false,sizeof(vis));

    for(int i=0;x-1-i>=i;i++)

    {

        int tmp=mex(i)^mex(x-1-i)^1;

        vis[tmp]=true;

    }

    for(int i=0;x-2-i>=i;i++)

    {

        int tmp=mex(i)^mex(x-2-i);

        vis[tmp]=true;

    }

    for(int i=0;;i++)

        if(!vis[i])

        {

            sg[x]=i;

            break;

        }

    return sg[x];

}

bool g[2][MAXN];

int main()

{

//    freopen("in.txt","r",stdin);

//    freopen("out.txt","w",stdout);

    memset(sg,-1,sizeof(sg));

    sg[0]=0;

    for(int i=1;i<5000;i++)

        sg[i]=mex(i);

    int T;

    scanf("%d",&T);

    int iCase=0;

    while(T--)

    {

        int n,m;

        scanf("%d%d",&n,&m);

        memset(g,false,sizeof(g));

        int u,v;

        while(m--)

        {

            scanf("%d%d",&u,&v);

            u--;v--;

            g[u][v]=true;

        }

        int len=0;

        int ans=0;

        for(int i=0;i<n;i++)

        {

            if(g[0][i]||g[1][i])

            {

                ans^=sg[len];

                len=0;

                if(g[0][i]&&g[1][i])continue;

                ans^=1;

            }

            else len++;

        }

        ans^=sg[len];

        iCase++;

        if(ans)printf("Case %d: Alice\n",iCase);

        else printf("Case %d: Bob\n",iCase);

    }

    return 0;

}
C

 

 

D:HDU 4560

我是歌手

最大流+二分

链接:

http://acm.hdu.edu.cn/showproblem.php?pid=4560

 这个题目的建图比较常规。

N个歌手编号为1~N

M种歌曲,拆点。编号分别为N+1~N+M,N+M+1~N+2*M

源点为0,汇点为N+2*M+1  总共N+2*M+2个点。

N+i 和  N+M+i  之间连权值为K的边,作为限制。

对于i, j  如果i对j擅长,那么连边 i -> N+M+j

否则连边 i -> N+j 这样就可以限制了。

 

然后是二分答案。

0~(1~N)之间,连边 mid .

(N+M+1~N+2*M)与N+2*M+1之间也连边mid

然后判断mid*N和最大流是不是相当。

 然后就是最大流模板题了。

 

 

 

 

//============================================================================

// Name        : D.cpp

// Author      : 

// Version     :

// Copyright   : Your copyright notice

// Description : Hello World in C++, Ansi-style

//============================================================================



#include <iostream>

#include <stdio.h>

#include <string.h>

#include <algorithm>

#include <queue>

#include <vector>

#include <map>

#include <set>

#include <string>

#include <math.h>

using namespace std;



const int MAXN=1100;

int maze[MAXN][MAXN];

int gap[MAXN],dis[MAXN],pre[MAXN],cur[MAXN];

int flow[MAXN][MAXN];//存最大流的容量

int sap(int start,int end,int nodenum)

{

    memset(cur,0,sizeof(cur));

    memset(dis,0,sizeof(dis));

    memset(gap,0,sizeof(gap));

    memset(flow,0,sizeof(flow));

    int u=pre[start]=start,maxflow=0,aug=-1;

    gap[0]=nodenum;

    while(dis[start]<nodenum)

    {

        loop:

          for(int v=cur[u];v<nodenum;v++)

            if(maze[u][v]-flow[u][v] && dis[u]==dis[v]+1)

            {

                if(aug==-1 || aug>maze[u][v]-flow[u][v])aug=maze[u][v]-flow[u][v];

                pre[v]=u;

                u=cur[u]=v;

                if(v==end)

                {

                    maxflow+=aug;

                    for(u=pre[u];v!=start;v=u,u=pre[u])

                    {

                        flow[u][v]+=aug;

                        flow[v][u]-=aug;

                    }

                    aug=-1;

                }

                goto loop;

            }

            int mindis=nodenum-1;

            for(int v=0;v<nodenum;v++)

               if(maze[u][v]-flow[u][v]&&mindis>dis[v])

               {

                   cur[u]=v;

                   mindis=dis[v];

               }

            if((--gap[dis[u]])==0)break;

            gap[dis[u]=mindis+1]++;

            u=pre[u];

    }

    return maxflow;

}



bool used[MAXN][MAXN];



int main()

{

//    freopen("in.txt","r",stdin);

//    freopen("out.txt","w",stdout);

    int T;

    int N,M,L,K;

    scanf("%d",&T);

    int iCase=0;

    while(T--)

    {

        iCase++;

        scanf("%d%d%d%d",&N,&M,&L,&K);

        memset(maze,0,sizeof(maze));

        int u,v;

        memset(used,false,sizeof(used));

        while(L--)

        {

            scanf("%d%d",&u,&v);

            used[u][v]=true;

        }

        for(int i=N+1;i<=N+M;i++)maze[i][i+M]=K;

        for(int i=1;i<=N;i++)

            for(int j=1;j<=M;j++)

            {

                if(used[i][j])

                {

                    maze[i][j+N+M]=1;

                }

                else maze[i][j+N]=1;

            }

        int ans=0;

        int l=0,r=M;

        while(l<=r)

        {

            int mid=(l+r)/2;

            for(int i=1;i<=N;i++)maze[0][i]=mid;

            for(int i=N+M+1;i<=N+2*M;i++)maze[i][N+2*M+1]=mid;

            if(sap(0,N+2*M+1,N+2*M+2)==mid*N)

            {

                ans=mid;

                l=mid+1;

            }

            else r=mid-1;

        }

        printf("Case %d: %d\n",iCase,ans);

    }





    return 0;

}
D

 

 

你可能感兴趣的:(HDU)