zoukankan      html  css  js  c++  java
  • 「CEOI2014」The Wall 题解

    「CEOI2014」 The Wall 题解

    题意

    (~~~~) 求在二维平面上选择一些有权值的线段并将给定的格子围住的最小权。

    (~~~~) (1leq n,mleq 400)

    本文版权归 Azazel 与博客园共有,欢迎转载,但需保留此声明,并给出原文地址,谢谢合作。

    原文地址:https://www.cnblogs.com/Azazel/p/15203410.html

    题解

    (~~~~) 神仙结论题目。

    (~~~~) 首先这道题的结论是:将每个方格四周的点按照权值连边后,所有关键格子左上角的点到最左上角的最短路一定被围住或是边界的一部分。

    (~~~~) 如何证明这个结论?考虑某个最优且某条最短路不被围住的方案:如图, (v) 为一关键格子,其中绿线为左上角到这个格子左上角的最短路,阴影部分为被圈住的区域。由于最短路的定义,则我们把选择红色线段的部分改为蓝色线段一定不会使花费更大,但与此同时被圈住的区域变大了,因此选择最短路一定是最优的。

    hGgSvq.png

    (~~~~) 知道了这个结论我们可以怎么做呢?考虑把原先的点继续拆成左上、右上、右下、左下四个点,同时保留原先的边。当不在原图中的两个点不会跨过所有最短路时这两个点就可以连一条 (0) 权边。同时注意第一个点拆出的左上不能与其他点连接。最后我们再跑一次从第一个点的右上到第一个点的左下的最短路就可以得到答案了。

    (~~~~) 比如下图就是样例一的转化后的图(每个点拆出来的点顺时针标号 (0 sim 3)

    hG2Opj.png

    代码

    查看代码
    #include <map>
    #include <queue>
    #include <cassert>
    #include <cstdio>
    #include <vector>
    #include <algorithm>
    #define ll long long
    #define PII pair<ll,ll>
    #define mp(a,b) make_pair(a,b)
    using namespace std;
    ll n,m;
    ll L1[405][405],L2[405][405];
    bool vil[405][405];
    bool vis[2000005];
    map<ll,bool>S[200000];
    ll dis[1000005],fa[1000005];
    vector < PII > G[1000005];
    inline ll ID(ll x,ll y){return (x-1)*(m+1)+y;}
    inline ll ID3(ll x,ll y,ll z){return ((x-1)*(m+1)+y-1)*4+z;}
    struct cmp{
    	bool operator()(const PII x,const PII y){return x.second>y.second;}
    };
    void Dij(ll N)
    {
    	priority_queue< PII,vector< PII >,cmp >Q;
    	for(ll i=1;i<=N;i++) vis[i]=0,dis[i]=999999999999999999;
    	Q.push(mp(1,0));dis[1]=0;
    	while(!Q.empty())
    	{
    		ll u=Q.top().first;Q.pop();
    		if(vis[u]) continue; vis[u]=true;
    		for(ll i=0;i<G[u].size();i++)
    		{
    			ll v=G[u][i].first,w=G[u][i].second;
    			if(!vis[v]&&dis[v]>dis[u]+w)
    			{
    				fa[v]=u;
    				dis[v]=dis[u]+w;
    				Q.push(mp(v,dis[v]));
    			}
    		}
    	}
    }
    template<typename T>void print(T x)
    {
        if(x<0) putchar('-'),x=-x;
        if(x>9) print(x/10);
        putchar(x%10+'0');
    }
    void Tag(ll u)
    {
    	while(u!=1)
    	{
    //		prllf("ban:%d %d
    ",fa[u],u);
    		S[fa[u]][u]=S[u][fa[u]]=true;
    		u=fa[u];
    	}
    }
    void AddEdge(ll u,ll v,ll w){G[u].push_back(mp(v,w)); G[v].push_back(mp(u,w));assert(v>=0);/*prllf("%d %d %d
    ",u,v,w);*/}
    int main() {	
    	scanf("%lld %lld",&n,&m);
    	for(ll i=1;i<=n;i++)
    		for(ll j=1;j<=m;j++) scanf("%d ",&vil[i][j]);
    	for(ll i=1;i<=n;i++)
    	{
    		for(ll j=1,x;j<=m+1;j++)
    		{
    			scanf("%lld",&x);L1[i][j]=x;
    			ll u=ID(i,j),v=ID(i+1,j);
    			G[u].push_back(mp(v,x));
    			G[v].push_back(mp(u,x));
    		}
    	}
    	for(ll i=1;i<=n+1;i++)
    	{
    		for(ll j=1,x;j<=m;j++)
    		{
    			scanf("%lld",&x);L2[i][j]=x;
    			ll u=ID(i,j),v=ID(i,j+1);
    			G[u].push_back(mp(v,x));
    			G[v].push_back(mp(u,x));
    		}
    	}
    	Dij((n+1)*(m+1));
    	for(ll i=1;i<=n+1;i++)
    		for(ll j=1;j<=m+1;j++) G[ID(i,j)].clear();
    	for(ll i=1;i<=n;i++)
    		for(ll j=1;j<=m;j++)
    			if(vil[i][j]) Tag(ID(i,j));
    	for(ll i=1;i<=n;i++)
    	{
    		for(ll j=1;j<=m+1;j++)
    		{
    			AddEdge(ID3(i,j,2),ID3(i+1,j,1),L1[i][j]);
    			AddEdge(ID3(i,j,3),ID3(i+1,j,0),L1[i][j]);
    			if(!S[ID(i,j)].count(ID(i+1,j)))
    			{
    				if(!vil[i][j-1]&&!vil[i][j]) AddEdge(ID3(i,j,2),ID3(i,j,3),0);
    				if(!vil[i][j-1]&&!vil[i][j]&&(i!=1||j!=1)) AddEdge(ID3(i+1,j,0),ID3(i+1,j,1),0);
    			}
    		}
    	}
    	for(ll i=1;i<=n+1;i++)
    	{
    		for(ll j=1;j<=m;j++)
    		{
    			AddEdge(ID3(i,j,1),ID3(i,j+1,0),L2[i][j]);
    			AddEdge(ID3(i,j,2),ID3(i,j+1,3),L2[i][j]);
    			if(!S[ID(i,j)].count(ID(i,j+1)))
    			{
    				if(!vil[i-1][j]&&!vil[i][j]) AddEdge(ID3(i,j,1),ID3(i,j,2),0);
    				if(!vil[i-1][j]&&!vil[i][j]&&(i!=1||j!=1))AddEdge(ID3(i,j+1,0),ID3(i,j+1,3),0);	
    			}
    		}
    	}
    	for(ll i=1;i<=m+1;i++)
    	{
    		if(i!=1) AddEdge(ID3(1,i,1),ID3(1,i,0),0);
    		AddEdge(ID3(n+1,i,2),ID3(n+1,i,3),0);
    	}
    	for(ll i=1;i<=n+1;i++)
    	{
    		if(i!=1) AddEdge(ID3(i,1,0),ID3(i,1,3),0);
    		AddEdge(ID3(i,m+1,1),ID3(i,m+1,2),0);
    	}
    	Dij((n+1)*(m+1)*4);
    	printf("%lld",dis[3]);
    	return 0;
    }
    
  • 相关阅读:
    Atitit 常用比较复杂的图像滤镜 attilax大总结
    Atitit usrQBM1603短信验证码规范
    Atitit usrQBM2331 参数格式化规范
    Atitit 函数式编程与命令式编程的区别attilax总结  qbf
    atitit 短信接口规范与短信解决方案.docx
    atitit  验证码理论与概览与 验证码规范 解决方案.docx
    Atiti  attilax主要成果与解决方案与案例rsm版 v4
    Atitit 作用域的理解attilax总结
    Atitit cms
    Atitit 图片 验证码生成attilax总结
  • 原文地址:https://www.cnblogs.com/Azazel/p/15203410.html
Copyright © 2011-2022 走看看