zoukankan      html  css  js  c++  java
  • 题解 P2176 [USACO11DEC]RoadBlock S / [USACO14FEB]Roadblock G/S

    P2176 [USACO11DEC]RoadBlock S / [USACO14FEB]Roadblock G/S

    好题,这道题有许多值得记录的细节。

    1. 在链式前向星中,记录邻接表边权的编号。
      这让我对邻接表结构有了更深的理解,原本以为,变量cnt的意义只是一个计数器,而当建图的过程完成后,cnt的历史记录是不可查的,也就是不可记忆化。
      可是事实并不是如此,若在题目中明确指出,两点之间不存在重边时,cnt就可以被记忆化。//存在重边应该也可以,设想应该要麻烦很多。
      思路:已知起点和终点,因为两点之间不存在重边,所以已知两点的编号,就可以找到对应的边的相关属性。所以只要在存边时,有意的记录下来点与cnt的关系,这个问题就解决了。
      PS:题目中,我用的是二维数组,是因为在这道题中,空间范围允许,二维数组最方便。其实最好的,是用pair或者自写结构体。

    2. 对于前驱的循环操作。

      for(int i=n;i;i=pre[i])//前驱的循环
      

      相对于写递归,这样写更清爽,而且应该也可以省空间。
      值得注意的是,这种写法对于整个图来说的反向的。

    3. 关于数组的初始化
      因为这个原因,这道题调了好久。
      以前总是认为,在全局中开数组是默认0。就懒的初始化。
      现在看,还是最好都初始化一下,因为有时需要进行多次操作。

    回到这题。

    思路:若扩大一条边,能使最短路增加,这条边一定在原最短路上。所以枚举最短路上的边,逐一扩大,然后重新跑最短路,然后得到增量。
    PS:千万不要重新建图,耗不起。

    #include <bits/stdc++.h>
    #define MAXN 200000
    #define INF 0x3f3f3f3f
    int n,m,cnt=0,ans=0;
    bool flag=1;
    int adj[MAXN],dis[MAXN],vis[MAXN],pre[MAXN];
    int linker[100][100];
    struct EDGE{int to,nxt,val;}	e[MAXN];
    struct node
    {
    	int pos,dis;
    	bool operator < (const node &x) const {return x.dis<dis;}
    };
    void addedge(int u,int v,int w)
    {
    	e[++cnt].to=v; e[cnt].nxt=adj[u]; e[cnt].val=w; adj[u]=cnt; linker[u][v]=cnt;
    }
    std::priority_queue < node > q;
    void Dijkstra()
    {
    	std::memset(vis,0,sizeof(vis));
            //vis数组清零
    	for(int i=1;i<=n;++i)	dis[i]=INF;
            //dis初始化
    	dis[1]=0; q.push((node){1,0});
    	while(!q.empty())
    	{
    		int u=q.top().pos;	q.pop();
    		if(vis[u])	continue;
    			vis[u]=1;
    		for(int i=adj[u];i;i=e[i].nxt)
    		{
    			int v=e[i].to;
    			if(dis[v]>dis[u]+e[i].val)
    			{
    				dis[v]=dis[u]+e[i].val;
    				if(flag) pre[v]=u;
    				if(!vis[v])	q.push((node){v,dis[v]});
    			}
    		}
    	}
    }
    
    int main()
    {
    	std::scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;++i) pre[i]=0;//前驱数组初始化
    	for(int i=1;i<=m;++i)
    	{
    		int u,v,w;	std::scanf("%d%d%d",&u,&v,&w);
    		addedge(u,v,w);	addedge(v,u,w);
    	}
    	Dijkstra();	int minn=dis[n]; flag=0;
    	for(int i=n;i;i=pre[i])//前驱的循环
    	{
    		int x=linker[i][pre[i]],y=linker[pre[i]][i];
    		e[x].val*=2;e[y].val*=2;
    		Dijkstra();
    		if(dis[n]!=INF) ans=std::max(ans,dis[n]-minn);
    		e[x].val/=2;e[y].val/=2;
    	}
    	std::printf("%d",ans);
    	return 0;
    }
    
  • 相关阅读:
    乱谈B2C系统算是今年的总结吧
    浅谈领域模型驱动中表的设计方法
    作业调度小软件
    使用Mutex实现会话状态下单实例运行和系统范围内单实例运行
    几种特殊的类型设计。
    XCommunity权限控制和配置体系
    某个最近不知道为啥很火的小题目的LINQ实现
    C#关于参数为null(空值)的方法调用,重载顺序选择彻底研究
    好吧,不得不说说这篇在首页恶心人的文章
    “九种不够面向对象的对象“的在实际项目中的合理运用
  • 原文地址:https://www.cnblogs.com/cyl-oi-miracle/p/13456473.html
Copyright © 2011-2022 走看看