2013腾讯编程马拉松初赛第5场(3月25)(HDU 4525 HDU4526 HDU4527 HDU4528 HDU4529)


    这次比赛题有点难。。我在谷大哥的帮助下把第一题A了。。斌哥在自己的努力下把第二题A了。。于是我们拿到了。。Rank 58 。。。。。。有点夸张啊。。。我最后看了看。。一共才180个人A出来题了。。。难道其他120个名额要分给那些疯狂刷wa的人??不叨叨了看题。。。


第一题:威威猫系列故事——吃鸡腿

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

题解:

#include <iostream>
#include <cmath>
using namespace std;
int main()
{
	int T, Case = 0;
	scanf("%d", &T);
	while (T--)
	{
		Case++;
		int n, k1, k2;
		__int64 k;
		__int64 sum = 0, sum1 = 0;
		scanf("%d %d %d %I64d", &n, &k1, &k2, &k);
		int i;
		__int64 tmp;
		for (i=0; i<n; i++)
		{
			scanf("%I64d", &tmp);
			sum += tmp;
		}
		printf("Case #%d: ", Case);

		sum1 = sum;
		for(i=0;;i++)
        {
            if(sum1 > k)
            {
                printf("%d\n",i);
                break;
            }
            sum = sum1;
            sum1 = sum*(k1+k2);
            if((sum >0 &&(k1+k2)>0 && sum1 <0))
            {
                printf("%d\n",i+1);
                break;
            }
            if((sum <0 &&(k1+k2)<0 && sum1 <0))
            {
                printf("%d\n",i+1);
                break;
            }
            if(i>100000)
            {
                printf("inf\n");
                break;
            }
        }
	}
	return 0;
}



第二题:威威猫系列故事——拼车记

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

题解:一下是斌哥AC代码

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 110;
int dp[maxn][maxn];
int n, k, d, s;
int cas;
int t[maxn], z[maxn];
int main(void)
{
   // freopen("f:\\code\\file\\data.txt", "r", stdin);
    scanf("%d", &cas);
    while(cas --)
    {
        scanf("%d%d%d%d", &n, &k, &d, &s);
        t[0] = 0;
        for(int i = 1; i <= k; i ++)
            scanf("%d%d", &t[i], &z[i]);
        for(int i = 0; i < maxn; i ++)
            dp[i][0] = 0;
        for(int i = 0; i < maxn; i ++)
        {
            for(int j = 1; j < maxn; j ++)
            {
                dp[i][j] = inf;
            }
        }
        for(int i = 1; i <= k; i ++)
        {
            for(int j = 1; j <= n; j ++)
            {
                dp[i][j] = dp[i - 1][j];
                for(int k = 1; k <= z[i]; k ++)if(j - k >= 0)
                {
                    dp[i][j] = min(dp[i - 1][j - k] + k * t[i] + d, dp[i][j]);
                }
            }
        }
        if(dp[k][n] == inf)
            printf("impossible\n");
        else
            printf("%d\n", dp[k][n]);
    }
    return 0;
}



第三题:小明系列故事——玩转十滴水

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

题解:(转自大牛:http://blog.csdn.net/dyx404514/article/details/8720661

思路:模拟题,要注意两个水珠同时到达一个4级水珠的情况,我用广搜过的,反正就是根据题意模拟,没什么好说的。代码如下:

#include <iostream>  
#include <string.h>  
#include <stdio.h>  
#include <algorithm>  
#include <queue>  
using namespace std;  
int bo[7][7];  
int dir[4][2]={1,0,0,1,-1,0,0,-1};  
int vis[7][7];  
int check(int x,int y)  
{  
    if(x<1||y<1||x>6||y>6)  
    return 0;  
    return 1;  
}  
void solve(int x,int y)  
{  
    queue<int> q;  
    bo[x][y]++;  
    if(bo[x][y]>4)  
    {  
        vis[x][y]=0;  
        q.push(x);  
        q.push(y);  
        q.push(0);//时间  
        q.push(-1);//方向  
    }  
    int i;  
    while(!q.empty())  
    {  
        int xx=q.front();q.pop();  
        int yy=q.front();q.pop();  
        int tt=q.front();q.pop();  
        int d=q.front();q.pop();  
            if(d==-1)  
            bo[xx][yy]=0;  
            for(i=0;i<4;i++)  
            {  
                if(d!=-1&&d!=i)  
                continue;  
                int x1=xx+dir[i][0],y1=yy+dir[i][1];  
                if(check(x1,y1))  
                {  
                    if(bo[x1][y1]==0)  
                    {  
                        q.push(x1);q.push(y1);q.push(tt+1);q.push(i);  
                    }  
                    else if(bo[x1][y1]<4)  
                    {  
                        bo[x1][y1]++;  
                    }  
                    else if(bo[x1][y1]==4)  
                    {  
                        bo[x1][y1]++;  
                        vis[x1][y1]=tt+1;  
                        q.push(x1);q.push(y1);q.push(tt+1);q.push(-1);  
                    }  
                    else  
                    {  
                        if(tt+1<=vis[x1][y1])  
                        bo[x1][y1]++;  
                        else  
                        {  
                            q.push(x1);q.push(y1);q.push(tt+1);q.push(i);  
                        }  
                    }  
                }  
            }  
    }  
  
}  
int main()  
{  
    //freopen("dd.txt","r",stdin);  
    while(scanf("%d",&bo[1][1])!=EOF)  
    {  
        int i,j,n,x,y;  
        for(i=1;i<=6;i++)  
        {  
            for(j=1;j<=6;j++)  
            {  
                if(i==1&&j==1)  
                continue;  
                scanf("%d",&bo[i][j]);  
            }  
        }  
        scanf("%d",&n);  
        while(n--)  
        {  
            scanf("%d%d",&x,&y);  
            memset(vis,-1,sizeof(vis));  
            solve(x,y);  
        }  
        for(i=1;i<=6;i++)  
        {  
            for(j=1;j<=6;j++)  
            {  
                if(j!=6)  
                printf("%d ",bo[i][j]);  
                else  
                printf("%d",bo[i][j]);  
            }  
            printf("\n");  
        }  
        printf("\n");  
    }  
    return 0;  
}



第四题:小明系列故事——捉迷藏

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

题解:(转自大牛:http://blog.csdn.net/dyx404514/article/details/8720661

:搜索题,明显的宽度搜索,设dist[x][y][0]表示当前没看到大明和二明到达(x,y)时的最早时间,dp[x][y][1]表示看到大明没看到二明的最早时间,dp[x][y][2]表示看到二明而没看到大明的最早时间。我们首先预处理一下能看到大明和能看到二明的位置,然后就搜就是了。这里要注意的是我们不能穿过一个人,也就是我们要把大明和二明当做障碍物,具体看样例3。代码如下:

#include <iostream>  
#include <string.h>  
#include <stdio.h>  
#include <algorithm>  
#include <queue>  
#define maxn 110  
#define inf 2100000000  
using namespace std;  
int dir[4][2]={1,0,0,1,-1,0,0,-1};  
int n,m;  
char bo[maxn][maxn];  
int check(int x,int y)  
{  
    if(x<1||y<1||x>n||y>m||bo[x][y]!='.')  
    return 0;  
    return 1;  
}  
int see[2][maxn][maxn];  
int dist[maxn][maxn][3];  
void init(int x,int y,int t)  
{  
    int i;  
    for(i=0;i<4;i++)  
    {  
        int xx=x+dir[i][0],yy=y+dir[i][1];  
        while(check(xx,yy))  
        {  
            see[t][xx][yy]=1;  
            xx+=dir[i][0];  
            yy+=dir[i][1];  
        }  
    }  
}  
int bfs(int x,int y)  
{  
    queue<int> q;  
    dist[x][y][0]=0;  
    int t,i;  
    if(see[0][x][y]&&see[1][x][y])  
    return 0;  
    q.push(x);  
    q.push(y);  
    q.push(0);  
    while(!q.empty())  
    {  
  
        int xx=q.front();q.pop();  
        int yy=q.front();q.pop();  
        int tt=q.front();q.pop();  
        int len=dist[xx][yy][tt];  
        //printf("%d %d\n",xx,yy);  
        if(see[0][xx][yy])  
        {  
            if(tt==2)  
            return len;  
            tt=1;  
        }  
         if(see[1][xx][yy])  
        {  
            if(tt==1)  
            return len;  
            tt=2;  
        }  
        for(i=0;i<4;i++)  
        {  
            int x1=xx+dir[i][0],y1=yy+dir[i][1];  
            if(check(x1,y1)&&dist[x1][y1][tt]==-1)  
            {  
                dist[x1][y1][tt]=len+1;  
                q.push(x1);  
                q.push(y1);  
                q.push(tt);  
            }  
        }  
  
    }  
    return inf;  
}  
int main()  
{  
    //freopen("dd.txt","r",stdin);  
    int ncase,time=0;  
    scanf("%d",&ncase);  
    while(ncase--)  
    {  
        printf("Case %d:\n",++time);  
        int t,i,j;  
        scanf("%d%d%d",&n,&m,&t);  
        for(i=1;i<=n;i++)  
        scanf("%s",bo[i]+1);  
        int sx,sy,x1,x2,y1,y2;  
        memset(see,0,sizeof(see));  
        for(i=1;i<=n;i++)  
        {  
            for(j=1;j<=m;j++)  
            {  
                if(bo[i][j]=='D')  
                x1=i,y1=j;  
                if(bo[i][j]=='E')  
                x2=i,y2=j;  
                if(bo[i][j]=='S')  
                {  
                    bo[i][j]='.';  
                    sx=i,sy=j;  
                }  
            }  
        }  
        memset(dist,-1,sizeof(dist));  
        init(x1,y1,0);  
        init(x2,y2,1);  
        //printf("f");  
        int ans=bfs(sx,sy);  
        if(ans>t)  
        printf("-1\n");  
        else  
        printf("%d\n",ans);  
    }  
    return 0;  
}



第五题:郑厂长系列故事——N骑士问题

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

题解:(转自大牛:http://hi.baidu.com/chenwenwen0210/item/6bcc70fc605fa4e4a835a28c

解题报告:

一看这数据范围就想到了状态压缩DP,由于马的攻击范围最多是上下2行。

所以我们只要管好前面两行的就行了,

dp[i][j][p][q]

表示第i行放马的状态是q,第i-1行的状态是p,前i行放马的个数是j个的种数。


推i+1行的时候枚举第i+1行放马的状态,进行转移。


总的复杂度无法估计,理论上是(1<<8)*(1<<8)*(1<<8)*n*8

这里需要一些剪枝,不然是通不过的。加了很多的非法判断。


#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<map>
#include<string>
#include<queue>
#include<stack>
#include<vector>
#include<set>
#include<list>
using namespace std;
typedef __int64 lld;
const int MAX=10;
const int INF=1000000000;
const double EPS=1.0e-8;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
int dblcmp(double x)
{
    if(fabs(x)<EPS)return 0;
    return x<0?-1:1;
}
int a[MAX];
lld dp[2][11][1<<8][1<<8];
char s[MAX];
bool ok1[1<<8][1<<8];
bool ok2[1<<8][1<<8];
bool judge(int a,int b,int d)
{
    int i;
    int x,y;
    for(i=0;i+d-1<8;i++)
    {
        x=1<<i;
        y=1<<i<<d;
        if((x&a)&&(y&b))return false;
        if((x&b)&&(y&a))return false;
    }
    return true;
}
int cnt[1<<8];
int count(int n)
{
    int ret=0;
    while(n)
    {
        ret+=n&1;
        n>>=1;
    }
    return ret;
}
int main(){
    
    int n=6;
    int i,j;
    int k;
    int T;
    int CS=1;
    for(i=0;i<(1<<8);i++)
    {
        for(j=0;j<(1<<8);j++)
        {
            ok1[i][j]=judge(i,j,1);
            ok2[i][j]=judge(i,j,2);
        }
    }
    for(i=0;i<(1<<8);i++)
    {
        cnt[i]=count(i);
    //    printf("cnt[%d]=%d\n",i,cnt[i]);
    }
    //printf("%d\n",1<<8);
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(i=0;i<8;i++)
        {
            scanf("%s",s);
            a[i]=0;
            for(j=0;j<8;j++)
            {
                a[i]*=2;
                if(s[j]=='*')a[i]++;
            }
        //    printf("a[%d]=%d\n",i,a[i]);
        }
    
        memset(dp,0,sizeof(dp));
        int xx=0;
        for(i=0;i<(1<<8);i++)
        {
            if(i&a[0])continue;
            if(cnt[i]>n)continue;
            dp[0][cnt[i]][0][i]++;
            xx++;
            //printf("i=%d\n",i);
        }
    //    printf("xx=%d\n",xx);
        int tag=0;
        for(i=1;i<8;i++)
        {
            tag=i&1;
            for(xx=0;xx<=n;xx++)
            {
                for(j=0;j<(1<<8);j++)
                {
                    for(k=0;k<(1<<8);k++)
                    {
                        dp[tag][xx][j][k]=0;
                    }
                }
            }
            for(j=0;j<(1<<8);j++)
            {
                if(i-2>=0&&(j&a[i-2]))continue;
    
                for(k=0;k<(1<<8);k++)
                {
                    if(k&a[i-1])continue;
    
                    if(cnt[j]+cnt[k]>n)continue;
                    if(!ok2[j][k])continue;
                    int tt;
                        
                    for(tt=cnt[j]+cnt[k];tt<=n;tt++)
                    {
                        if(dp[1-tag][tt][j][k]==0)continue;
    
                        for(int z=0;z<(1<<8);z++)
                        {
                            if(cnt[z]+tt>n)continue;
                            if(z&a[i])continue;
                            if(!ok2[z][k]||!ok1[z][j])continue;
                            dp[tag][tt+cnt[z]][k][z]+=dp[1-tag][tt][j][k];
                        }
                    }
                }
            }
    
        }
    
        lld ans=0;
        for(i=0;i<(1<<8);i++)
        {
            for(j=0;j<(1<<8);j++)
            {
                //if(dp[tag][n][i][j]>0)printf("%d %d\n",i,j);
                ans+=dp[tag][n][i][j];
            }
        }
        printf("%I64d\n",ans);
    }
    return 0;
}
/*
2
1
*.......
....*...
.......*
.....*..
..*.....
......*.
.*......
...*....
    
    
2
1
........
........
........
........
........
........
........
........
    
2
1
*******.
********
********
********
********
********
********
********
*/




评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值