• 【洛谷P1606】白银莲花池【最短路】


    题目大意:

    题目链接:https://www.luogu.org/problemnew/show/P1606
    一个n×mn imes m的网格中有一些点可以踩,另一些点不可以踩。一个人每次走动会以“日”字型走动,求最少要将几个点改变成可以踩的点才可以使得这个人可以从SS点到达TT点,以及方案数。


    思路:

    第一问能马上想到bfsbfs,但是第二问显然是最短路计数,所以考虑第一问也用最短路做。
    最简单的思想就是每一个点往外面8个日字型点连边,若是不可踩的点边权为1,否则边权为0。但是这样最短路计数时会少算一些重复的点,导致答案错误。
    所以考虑把边权为0的边去掉,只留下边权为1的边。所以可以考虑用dfsdfs建边。对于每一个点,用dfsdfs找到所有的与它距离为1的点,然后连边即可。
    接下来就是套 最短路模板最短路计数模板 了。


    代码:

    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #define mp make_pair
    using namespace std;
    typedef long long ll;
    
    const int N=40,M=500010;
    const int dx[]={0,-2,-1,1,2,-2,-1,1,2};
    const int dy[]={0,-1,-2,2,1,1,2,-2,-1};
    int n,m,S,T,tot,map[N][N],head[N*N],dis[N*N];
    ll cnt[N*N];
    bool vis[N*N];
    
    struct edge
    {
    	int next,to,dis;
    }e[M]; 
    
    int C(int x,int y)
    {
    	return (x-1)*m+y;
    }
    
    void add(int from,int to,int dis)
    {
    	e[++tot].to=to;
    	e[tot].dis=dis;
    	e[tot].next=head[from];
    	head[from]=tot;
    }
    
    void dfs(int root,int x,int y)
    {
    	if (vis[C(x,y)]) return;
    	vis[C(x,y)]=1;
    	for (int i=1;i<=8;i++)
    	{
    		int xx=x+dx[i],yy=y+dy[i];
    		if (xx>=1 && xx<=n && yy>=1 && yy<=m && !vis[C(xx,yy)])
    		{
    			if (map[xx][yy]==1) dfs(root,xx,yy);
    			else if (map[xx][yy]!=2)
    			{
    				add(root,C(xx,yy),1);
    				vis[C(xx,yy)]=1;
    			}
    		}
    	}
    }
    
    void dij()
    {
    	memset(dis,0x3f3f3f3f,sizeof(dis));
    	memset(vis,0,sizeof(vis));
    	priority_queue<pair<int,int> > q;
        q.push(make_pair(0,S));
        dis[S]=0;
        cnt[S]=1;
        while (q.size())
        {
            int u=q.top().second;
            q.pop();
            if (vis[u]) continue;
            vis[u]=1;
            for (int i=head[u];~i;i=e[i].next)
            {
                int v=e[i].to;
                if (dis[v]>dis[u]+e[i].dis)
                {
                    dis[v]=dis[u]+e[i].dis;
                    cnt[v]=cnt[u];
                    q.push(make_pair(-dis[v],v));
                }
                else if (dis[v]==dis[u]+e[i].dis)
                	cnt[v]+=cnt[u];
            }
        }
    }
    
    int main()
    {
    	freopen("data.in","r",stdin);
    	memset(head,-1,sizeof(head));
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=m;j++)
    		{
    			scanf("%d",&map[i][j]);
    			if (map[i][j]==3) S=C(i,j);
    			if (map[i][j]==4) T=C(i,j);
    		}
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=m;j++)
    			if (map[i][j]!=1&&map[i][j]!=2)
    			{
    				memset(vis,0,sizeof(vis));
    				dfs(C(i,j),i,j);
    			}
    	dij();
    	if (dis[T]<1e9) cout<<dis[T]-1<<endl<<cnt[T]<<endl;
    		else printf("-1
    ");
    	return 0;
    }
    
  • 相关阅读:
    关于苹果IPhone/Ipad(IOS)开发者证书申请及安装、真机调试、发布的参考文章
    vs 关闭警告
    真机测试及布署Code Sign error问题总结
    在 Win32 Application 和 Win32 Console Application 中使用 MFC
    获取应用程序路径的区别
    js日期控件
    SQL SERVER 企业管理器 MMC 无法创建管理单元
    进程查看两利器
    用PowerDesigner逆向数据库工程时”Unable to list the table"错误的解决方法
    SQL 附加无日志数据库
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998135.html
Copyright © 2020-2023  润新知