HDU 4308 Saving Princess claire_

题意:

给你一个r*c<5000的方格网络,从起点Y走到终点C,遇到#不能走,遇到*需要花费cost的钱。

解法:

建一个图然后跑一个最短路

坑点:

1. 建图的时候可以把边界设为其他字母,手残了第二个的行列写反了

2. 然后把P看成S

3.然后注意建图的时候起点和终点的特殊处理,起点只能往外连边,终点只能由别人连过来。

4.不连通的直接不加边,不是加成INF

5.把传送点S全部看成一个点而不是互相连花费为0的边

7.注意在算最短路的时候从的点数是r*c+1,把二维降成一维需要仔细


1Y好开心~

AC代码:

<span style="font-size:18px;">#include <cstdio>
#include <cstring>
#include <vector>
#include <vector>
#include <queue>
#include <iostream>
using namespace std;

const int maxn=5005;
const int INF=0x3f3f3f3f;
char map[maxn][maxn];
int dir[4][2]={-1,0,0,-1,0,1,1,0};
int r,c,cost;
 
struct heapnode
{
    int d,u;
    bool operator < (const heapnode &rhs) const
    {
        return d>rhs.d;
    }
};
struct Point
{
	int x,y;
}Y,C,P[maxn];

struct D
{
    int tot;
    int g[maxn*4],w[maxn*4],next[maxn*4];
    int head[maxn];
    bool done[maxn];
    int d[maxn];
 
    void init()
    {
        tot=0;
        memset(head,-1,sizeof(head));
        //for(int i=0;i<=n;i++)head[i]=-1;
    }
    void addedge(int from,int to,int dist)
    {
        tot++;g[tot]=to;w[tot]=dist;next[tot]=head[from];head[from]=tot;
    }
    void dijstra(int s)
    {
        priority_queue<heapnode>q;
        while(!q.empty())q.pop();
        for(int i=1;i<=c*r+1;i++)d[i]=INF;
        d[s]=0;
        memset(done,0,sizeof(done));
        heapnode tmp;
        tmp.d=0;
        tmp.u=s;
        q.push(tmp);
        while(!q.empty())
        {
            heapnode x=q.top();
            q.pop();
            int u=x.u;
            if(done[u])continue;
            done[u]=true;
            for(int i=head[u];i!=-1;i=next[i])
            {
                int v=g[i],l=w[i];
                if( d[u]<INF && d[v]>d[u]+l)
                {
                    d[v]=d[u]+l;
                    tmp.d=d[v];tmp.u=v;
                    q.push(tmp);
                }
            }
        }
       /*for(int i=1;i<=c*r+1;i++)
       {
       		cout<<i<<"  "<<d[i]<<endl;
       }*/
       if(d[(C.x-1)*c+C.y]==INF)
       		printf("Damn teoy!\n");
       else
       		printf("%d\n",d[(C.x-1)*c+C.y]);
    }
}a;

int main()
{
	while(scanf("%d %d %d",&r,&c,&cost)!=EOF)
	{
		int i,j,k,cnt=0;
		a.init();
		getchar();

		for(i=0;i<=r+1;i++)
			map[i][0]=map[i][c+1]='N';
		for(j=0;j<=c+1;j++)
			map[0][j]=map[r+1][j]='N';

		for(i=1;i<=r;i++)
		{
			for(j=1;j<=c;j++)
			{
				scanf("%c",&map[i][j]);
				if(map[i][j]=='Y')
					Y.x=i,Y.y=j;
				else if(map[i][j]=='C')
					C.x=i,C.y=j;
				//else if(map[i][j]=='S')
					//P[cnt].x=i,P[cnt++].y=j;
			}
			getchar();
		}
		/*for(i=0;i<=c+1;i++)
		{
			for(j=0;j<=c+1;j++)
				printf("%c",map[i][j]);
			printf("\n");
		}*/
		int tx,ty;
		bool f=false;
		for(k=0;k<4;k++)
		{
			tx=Y.x+dir[k][0];
			ty=Y.y+dir[k][1];
			if(map[tx][ty]=='N') continue;
			if(tx==C.x && ty==C.y) 
				{
					printf("0\n");
					f=true;
					break;
				}
			if(map[tx][ty]=='*')
				a.addedge((Y.x-1)*c+Y.y,(tx-1)*c+ty,cost);
			else if(map[tx][ty]=='P')
				a.addedge((Y.x-1)*c+Y.y,r*c+1,0);

		}

		if(f) continue;
		for(i=1;i<=r;i++)
			for(j=1;j<=c;j++)
			{
				if(i==Y.x&&j==Y.y) continue;
				if(i==C.x&&j==C.y) continue;
				for(k=0;k<4;k++)
				{
					tx=i+dir[k][0];
					ty=j+dir[k][1];
					if(map[tx][ty]=='N' || map[tx][ty]=='#' ||tx==Y.x&&ty==Y.y ) continue;
					//if(i==Y.x&&J==Y.y) continue;
					if(map[i][j]=='*')
					{
						if(map[tx][ty]=='*')
							a.addedge((i-1)*c+j,(tx-1)*c+ty,cost);
						else if(C.x==tx&&C.y==ty)
							a.addedge((i-1)*c+j,(tx-1)*c+ty,0);
						else
							a.addedge((i-1)*c+j,r*c+1,0);
					}
					else if(map[i][j]=='P')
					{
						if(map[tx][ty]=='*')
							a.addedge(r*c+1,(tx-1)*c+ty,cost);
						else if(C.x==tx&&C.y==ty)
							a.addedge(r*c+1,(tx-1)*c+ty,0);
					}

				}
			}
		/*for(i=0;i<cnt;i++)
			for(j=0;j<cnt;j++)
			{
				a.addedge((P[i].x-1)*c+P[i].y,(P[j].x-1)*c+P[j].y,0);
			}*/
		a.dijstra((Y.x-1)*c+Y.y);
	}
	return 0;
}</span>





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值