HDU3035-平面图最小割转最短路

PS:这是get姿势后的第一道建图稍微麻烦的题,居然写完代码没调试一次AC了~~~哈哈~~~~


War

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1386    Accepted Submission(s): 403


Problem Description
Country X is under attack by enemies. Now the army of enemy has arrived at City Y. City Y consists of an N×M grid. All the paths in the grid are bidirectional, horizontal or vertical or diagonal. The upper-left corner is (0, 0) and lower-right corner is (N, M). The army enters at (0, 0) and they must get to (N, M) in order to continue their attack to the capital of Country X. The figure below shows what does City Y looks like.

Every blackened node represents a vertex. The number beside each edge is the amount of TNT needed to destroy that road. The army of Country X is unable to beat the enemy now. The only thing they can do is to prevent them from heading to their capital so that they can have more time to prepare for striking back. Of course they want to use the least amount of TNT to disconnect (0, 0) and (N, M). You are a talented programmer, please help them decide the least amount needed.
 

Input
There are multiple test cases.

The first line of each test case contains two positive integers N and M, representing height and width of the grid.

Then N+1 lines each containing M integers, giving you the amount needed of horizontal roads in row major order.

Then N lines each containing M+1 integers, giving you the amount needed of vertical roads in row major order.

Then 2N lines each containing 2M integers, giving you the amount needed of diagonal roads in row major order.

There is a blank line after each input block. The sample input is corresponding to the figure above.

Restriction:

1 <= N, M <= 500

1 <= amount <= 1,000,000
 

Output
One line for each test case the least amount of TNT needed to disconnect (0, 0) and (N, M).
 

Sample Input
2 3 1 9 4 1 8 7 6 2 3 7 5 4 8 6 2 8 7 10 4 1 7 5 3 5 4 10 2 1 9 6 3 2 9 5 3 8 9 6 3 10 10
 

Sample Output
18
 

Source


题目思路:

                    s-t平面图最小割转最短路的裸题,具体可以参见我之前写的博客:   s-t平面图最小割转最短路算法

                    这题我们很容易可以得到对偶图的点的个数为n*m*4+2 ,边的个数为n*m*4+n*m*2+n+m-2,

                    所以如果用普通的spfa的话会超时,因此我们这里要用优先队列优化,这里编号的话我们可以

                    以0点为S*,n*m*4+1为T*,然后中间每个大格子中的四个小格子编号可以1 2 3 4 这样按顺序排

                    从上到下,从左到右! 注意下细节,应改建起图还是不难的!


AC代码:


#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>

using namespace std;

const int maxn = 1e6+100;
const int inf = 1e9;

struct nod{
   int v,w,nex;
}edge[maxn<<2];

int n,m,nn,e,k;
int dis[maxn],hed[maxn];
bool vis[maxn];

void add(int u,int v,int w){
    edge[e].v = v,edge[e].w = w,edge[e].nex = hed[u],hed[u]=e++;
    edge[e].v = u,edge[e].w = w,edge[e].nex = hed[v],hed[v]=e++;
}

void dij(){
   for(int i=0;i<=nn;i++)
    dis[i]=inf,vis[i]=0;
   dis[0]=0;
   priority_queue<pair<int,int > >q;
   q.push(make_pair(-dis[0],0));
   while(!q.empty()){
        int u = q.top().second;q.pop();
        if(vis[u])continue;vis[u]=1;
        for(int i=hed[u];~i;i=edge[i].nex){
            int v = edge[i].v;
            if(dis[v]>dis[u]+edge[i].w){
                dis[v]=dis[u]+edge[i].w;
                if(!vis[v]){
                    q.push(make_pair(-dis[v],v));
                }
            }

        }
   }
}

int main()
{
    while(~scanf("%d%d",&n,&m)){
        nn = n*m*4+1;e=0;
        memset(hed,-1,sizeof(hed));
        for(int i=1;i<=n+1;i++){
            for(int j=1;j<=m;j++){
                scanf("%d",&k);
                if(i==1)                  //最上面的边
                    add(nn,(j-1)*4+1,k);   
                else if(i==n+1)            //最下面的边
                    add(0,(n-1)*m*4+(j-1)*4+3,k);
                else                       //中间水平的边
                    add((i-2)*m*4+(j-1)*4+3,(i-1)*m*4+(j-1)*4+1,k);
            }
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m+1;j++){
                scanf("%d",&k);
                if(j==1)                 //最左面的边
                    add(0,(i-1)*m*4+2,k);
                else if(j==m+1)            //最右面的边
                    add(nn,i*m*4,k);
                else                        //中间垂直的边
                    add((i-1)*m*4+(j-1)*4,(i-1)*m*4+(j-1)*4+2,k);
            }
        }
        for(int i=0;i<2*n;i++){
            for(int j=0;j<2*m;j++){
                scanf("%d",&k);
                //中间斜着的边,这个公式在图上画画应该不难推
                add(i/2*m*4+j/2*4+1+(i%2)*2,i/2*m*4+j/2*4+2+(j%2)*2,k);
            }
        }
        dij();
        printf("%d\n",dis[nn]);
    }
    return 0;
}





全部评论

相关推荐

2025-12-31 19:23
已编辑
门头沟学院 Java
ssob是已读不回的,字节是压根不敢投的,简历是反反复复改了N遍的,八股是永远背不完的😅😅😅扯远了,道心破碎了,把简历发出来让大伙先看看笑话。再说正事。寒假日常实习还是很难找,连个面试都难约,我不是个例,这是网上普遍反映。不报希望了,趁着2、3月前赶紧做些什么才是。扔几个碎碎念:1.这破简历还能怎么改?写到什么程度才能过实习岗筛选?广大牛友来锐评一下2.火速辅修go,是否可行目前看来是学习成本最小的。首先,很多go实习岗位已经明确要求掌握gin等技术栈,拿java简历投go的时代已经过去了。其次,很多后端的东西,MySQL、Redis这些都是通用的,不用重新学。所以这个问题就具体为:2.1&nbsp;java&amp;go混血简历怎么写第一个项目,仿大麦的微服务,不太好改。因为有用到Redisson、AOP、SpringAI这些java强相关的东西,包装成go需要替换这些方案。第二个,点评魔改。应该可以包装成go,github上也有人用go重写过。2.2&nbsp;java&amp;go通用的轮子RPC直接pass了,太烂大街了。不知道动态线程池能不能做。反正项目上新有风险,不一定来得及,非必要就不开新的项目。补充:别跟我扯RAG了,这玩意已经成新的烂大街了,详见我上一篇的吐槽。3.认真学微调prompt什么的这个半步踩进算法了已经。八股和场景题完全就是另一套,没两三个月搞不定的。约等于换方向
简历中的项目经历要怎么写
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务