【图论专题】8.10~8.12 你见过大蒟蒻写题解吗?点进来你就见过了!

8.10号我们做了一套图论模拟题,是学长从各个OJ上扒来的…ACM赛制,十道题,一天QAQ

然后我喜闻乐见的跪了,一天只A了四道,罚时突破天际(:з」∠)【其实到了最后完全不顾罚时,就当平常练习交OJ了…

之后两天才A了全十道题QAQ

以下是个人对题目的见解

A:
POJ 2312
题意:给你一个n*m的地图,给定起点终点,地图上有地面、河流、 铁墙、土墙,可以向土墙发射炮弹打成平地算一次操作,每走一步算一次操作,求起点到终点的最少操作步数。

乍一看是裸的迷宫题,考试时当迷宫打的QAQ然而妥妥T了,n,m<=300+多组询问……本以为加一个很弱的A*优化能过,结果还是T……

正解是spfa:读入后建图,把二维的点映射到一维的点,以某点为起点向四个方向建边,若到达的点为土墙则权值为2,否则权值为1,然后跑一边spfa即可……

B:
POJ 2367

大水题,我这么弱还读完题就A了…一遍拓扑排序,完了。【第一次打拓扑排序,复杂度n^2都能过】

C:
POJ 1797
题意:给定一张n个点,m条边的无向图,每条边有一个重量上限,求从起点1到终点n能够运输的最大的重量。

spfa松弛那里改一下即可,稍微想一下即可A掉
这种我也是第一次打,可能有些地方打的比较奇怪…但是A了233

松弛操作:

if(dist[v]<min(dist[u]+l[I].d))
{
    dist[v]=min(dist[u],l[i].d)
    if(!use[v]) q.push(v),use[v]=1;
}

大概还有其他细节,自行处理。

D:
HDU 3873
你要摧毁一个国家的首都,给定城市之间连通方式,并且每个城市受别的城市保护,只有摧毁所有保护此城市的城市,才可以摧毁此城市。从起点开始可以向多个方向同时出击,求摧毁首都最短用时。
总之就是有节点保护的最短路。

我太弱,考场上没写出来,写了个很迷的spfa+dfs取max,然而WA。后来找的题解…

记录节点u被保护次数为bh[u],记录pro[u]为保护u结点的dist的最大值。用dijstra跑最短路,因为第一个到达的节点是最优的(贪心),所以每到达一个结点u就把它保护的结点v的bh[v]--,同时更新pro[v],若某一点的bh值为0且dist不为INF,则push进去更新其他点。再遍历一下所连到的点,到那个点的距离为max(dist[v]+l[i].d,pro[u])

        for(int i=0;i<g[f].size();i++)
        {
            int v=g[f][i];
            bh[v]--;
            pro[v]=max(pro[v],dist[f]);
            if(bh[v]==0&&dist[v]!=INF)
            {
                dist[v]=max(pro[v],dist[v]);
                q.push((Heap){v,dist[v]});
            }
        }
        for(int i=head[f];i;i=nxt[i])
        {
            int v=l[i].t;
            if(dist[v]>dist[f]+l[i].d)
            {
                dist[v]=max(dist[f]+l[i].d,pro[v]);
                if(!bh[v]) q.push((Heap){v,dist[v]});
            }
        }

E:
POJ 3159
分糖,要满足多个约束条件,类似于a不希望b拿到的糖比a多c块【当然可以a比b拿得多】。求满足所有约束条件的同时N号拿的糖果与1号的最大差值。

第一眼看就是差分约束,关系就是满足b-a<=c。建图解决了,但针对答案还是纠结了好久。
我差分约束的题做的不多,我都是新建一个起点向所有的点连边权为0的边跑最短路,最后的dist数组即为一组可行解。并且同时加任意常数k也是一组可行解。
但这个题是求最大差距,一开始我还想新建起点跑最短路/最长路瞎搞,果断不行。但答案也可以这样看:当1号的解为0时,使N号解最大的dist[n]。
那么,就相当于dist[1]=0了,所以说就可以以1号点为起点跑最短路,输出dist[n]即可。

跑不出最短路就是无解QAQ然而题保证有解。

F:
POJ 3463

求最短路路径条数和长度为 最短路+1 的路径条数之和。

计算最短路路径条数和次短路路径条数,输出时判断次短路是否等于最短路+1。这个想法很显然。

关键是如何记录路径条数。一开始打了K短路想水过去,结果果断T,然后考场上就没时间打了…
dijstra来转移。一共就四种情况:
①最短路可以更新最短路
因为dijstra找到此点第一次肯定是最优的,于是用最短路更新最短路,把原来的最短路放到次短路里,记录路径条数的数组也是这样。别忘了push。
②最短路等于最短路
路径条数++。不需要push
③次短路可以更新次短路
更新次短路,路径数组,push。
④次短路等于次短路
次短路路径条数++。不push

void dij(int s)
{
    for(int i=1;i<=n;i++) dist[i][1]=dist[i][0]=INF;
    dist[s][0]=0;
    num[s][0]=1;
    q.push((Heap){s,0,0});
    while(q.size())
    {
        int f=q.top().u;//int k=q.top().k;//0:最短路,1:次短路
        int d=q.top().d;//dist
        q.pop();
        if(use[f][k]) continue;
        use[f][k]=1;
        for(int i=head[f];i;i=nxt[i])
        {
            int v=l[i].t;
            if(dist[v][0]>d+l[i].d)
            {
                if(dist[v][1]>dist[v][0])
                {
                    dist[v][1]=dist[v][0];
                    num[v][1]=num[v][0];
                    q.push((Heap){v,1,dist[v][1]});
                }
                dist[v][0]=d+l[i].d;
                num[v][0]=num[f][0];
                q.push((Heap){v,0,dist[v][0]});
            }
            else if(dist[v][0]==d+l[i].d)
            {
                num[v][0]+=num[f][0];
            }
            else if(dist[v][1]>d+l[i].d)
            {
                dist[v][1]=d+l[i].d;
                num[v][1]=num[f][k];
                q.push((Heap){v,1,dist[v][1]});
            }
            else if(dist[v][1]==d+l[i].d)
            {
                num[v][1]+=num[f][k];
            }
        }
    }
}

G:
POJ 1860
题目大意:现有N种货币,M个兑换点,每个兑换点可以将某种货币按一定汇率兑换成另一种货币,但是要收取一定手续费。具体来说:A到B的汇率是指你能用1A换到的B的数量。手续费按源货币收取,例如你想把100美元(USD)换成俄罗斯卢布(RUR),汇率是29.75,手续费是0.39,那么你能换得(100-0.39)*29.75=2963.3975 RUR。从不同兑换点兑换同种货币可能有不同的汇率和手续费。现在你有V单位的货币S,你想知道是否存在一种兑换方案,使得经过一系列兑换后你能换得更多的货币S。

就是找正环…bellmanFord,在n-1次循环后还可以继续更新则说明有正环。

H:
POJ 1511
给定一张有向图,给定起点1,求起点到所有其他点来回的最短路的长度之和。

大水题,跑一遍spfa 后反向建边再跑一遍,两遍得出来的dist数组暴力相加即为答案。

I:
HDU 3938
ZLGG发现了一个神奇的定理:香蕉越大,香蕉皮越大。运用这个重要的定理他可以在他的学校建立一对传送门。不幸的是,在U和V之间建立一对传送门要花费min{T}单位能量。一条路径中的T是从U到V的一条路径中最长的边的长度。两点间可能有多条路径。ZLGG拥有L单位能量,他想知道他有多少种不同的建造传送门的方案。

这个题是一个特别好的最小生成树的题,因为单看题面完全看不出来是最小生成树…
考虑只有一组询问的时候。边权大于L的边可以忽略。若A集合有a个点,B集合有b个点,则跨AB两集合的传送门建造方案则为a*b。
多组询问怎么办?离线大法好。将多组询问按L由小到大排序,然后做克鲁斯卡尔,两集合合并时更新答案。

        for(int i=1,j=1;i<=q;i++)
        {
            ans[i].ans=ans[i-1].ans;

            for(;j<=m&&ans[i].l>=l[j].d;j++)
            {
                int x=find(l[j].f);
                int y=find(l[j].t);
                if(x!=y)
                {
                    fa[x]=y;
                    ans[i].ans+=num[y]*num[x];
                    num[y]+=num[x];
                    num[x]=0;
                }   
            }
        }

J:
POJ 3114
最短路,相同强连通分量距离为0。

超烦的一个题,因为我拍了几万组数据都没问题,交上去就WA…缩点+最短路,没什么好说的。

要注意重建图的时候不要和原图混淆。
还有就是缩点之后Floyd过不了……

你可能感兴趣的:(ACM,poj,图论,差分约束,noip)