最短路专题

今天又多了两个专题 数论专题一题都没做就又有新得了
直接开一个专题来记录过的题把
以前数据结构那些写的很散

A - Til the Cows Come Home

最短路水题 直接过

B - Frogger

这题题意都没看懂一开始
看了题解顺便重新学了一下弗洛伊德的写法
不过这题很多毒瘤的地方
最后的输出要多加一个换行符 还有最好用c++
g++无限wa 换c++就a了

这题要求每个路径的最大值中间的最小值
因为数据不大 所以用弗洛伊德暴力跑就行了

ac代码

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <string.h>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <utility>
#define pi 3.1415926535898
#define ll long long
#define lson rt<<1
#define rson rt<<1|1
#define eps 1e-6
#define ms(a,b) memset(a,b,sizeof(a))
#define legal(a,b) a&b
#define print1 printf("111\n")
using namespace std;
const int maxn = 300+10;
const int inf = 0x1f1f1f1f;
const ll llinf =0x3f3f3f3f3f3f3f3f;
const int mod = 2333;

double mp[maxn][maxn];
int n;

struct node
{
    int x,y;
}e[maxn];


double cal(int x1,int y1,int x2,int y2)
{
    return sqrt((double)(x1-x2)*(x1-x2)+(double)(y1-y2)*(y1-y2));
}


int main()
{
    int ce=1;
    while(~scanf("%d",&n)&&n)
    {
        ms(mp,0);
        for(int i=1;i<=n;i++)
            scanf("%d%d",&e[i].x,&e[i].y);
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++)
                mp[i][j]=mp[j][i]=sqrt((double)(e[i].x-e[j].x)*(e[i].x-e[j].x)+(double)(e[i].y-e[j].y)*(e[i].y-e[j].y));
        for(int k=1;k<=n;k++)
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    mp[i][j]=min(mp[i][j],max(mp[i][k],mp[k][j]));//维护所有路径的最大值中的最小值
        printf("Scenario #%d\nFrog Distance = %.3lf\n\n",ce++,mp[1][2]);//这里最后记得多写一个换行符
    }
    return 0;
}

C - Heavy Transportation

题目思路

跟上题思路相似
不过这题是求每条路的最小值中间的最大值
因为数据变大了
所以好像弗洛伊德跑不了了
看了好多题解都是用的dij
但是我看了好久他中间的操作还是不是很明白
看完现在头还是晕的
先放代码上来
等我懂了在写注释把

ac代码

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <string.h>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <utility>
#define pi 3.1415926535898
#define ll long long
#define lson rt<<1
#define rson rt<<1|1
#define eps 1e-6
#define ms(a,b) memset(a,b,sizeof(a))
#define legal(a,b) a&b
#define print1 printf("111\n")
using namespace std;
const int maxn = 1000+10;
const int inf = 0x1f1f1f1f;
const ll llinf =0x3f3f3f3f3f3f3f3f;
const int mod = 2333;

int n,m;
int dis[maxn];
int mp[maxn][maxn],vis[maxn];

void dij()
{
    for(int i=1;i<=n;i++)
    {
        dis[i]=mp[1][i];
        vis[i]=0;
    }
    for(int i=1;i<=n;i++)
    {
        int tem=-1;
        int x=-1;
        for(int j=1;j<=n;j++)
        {
            if(!vis[j]&&dis[j]>tem)
            {
                tem=dis[j];
                x=j;
            }
        }
        if(x!=-1)
        {
            vis[x]=1;
            for(int j=1;j<=n;j++)
            {
                if(!vis[j]&&dis[j]<min(dis[x],mp[x][j]))
                    dis[j]=min(dis[x],mp[x][j]);
            }
        }
    }


}
int main()
{
    int t,ce=1;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        ms(mp,0);
        for(int i=1;i<=m;i++)
        {
            int x,y;
            int z;
            scanf("%d%d%d",&x,&y,&z);
            if(mp[x][y]<z)
            {
                mp[x][y]=z;
                mp[y][x]=z;
            }
        }
        dij();
        printf("Scenario #%d:\n",ce++);
        printf("%d\n\n",dis[n]);
    }
    return 0;
}

自闭专题继续更新

D - Silver Cow Party

题目思路 他要求每个点到x点的距离与x点到每个点的距离之和的最大值
因为题目给边都是单向的 所以就要特殊处理
一开始准备准备每个点跑一边 建一个dij的二维数组记录每次的值
但是一直wa 不知道那里错了
然后看了下题解说正着建一个图 在反着建一个图就好
在两个图上都跑一次dij就好了
题解给的是邻接矩阵的代码
但是我写的一直wa 也找不出哪里错了
就写了个前向星建两个图的 就是有点麻烦 写的时候要细心写不然很容易出bug

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <string.h>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <utility>
#define pi 3.1415926535898
#define ll long long
#define lson rt<<1
#define rson rt<<1|1
#define eps 1e-6
#define ms(a,b) memset(a,b,sizeof(a))
#define legal(a,b) a&b
#define print1 printf("111\n")
using namespace std;
const int maxn = 1e3+10;
const int inf = 0x1f1f1f1f;
const ll llinf =0x3f3f3f3f3f3f3f3f;
const int mod = 2333;

int n,m,x,first[maxn],first2[maxn],len1,len2;
int dis1[maxn],dis2[maxn];
int vis[maxn];
struct node
{
    int to,next,v;
}e[100000+10],re[100000+10];

void add(int u,int v,int w)
{
    e[len1].to=v;
    e[len1].next=first[u];
    e[len1].v=w;
    first[u]=len1++;

    re[len2].to=u;
    re[len2].next=first2[v];
    re[len2].v=w;
    first2[v]=len2++;
}

struct point
{
    int id;
    ll val;
    point(int id,ll val)
    {
        this->id=id;
        this->val=val;
    }
    bool operator<(const point &x)const
    {
        return val>x.val;
    }
};

void dij1(int s)
{
    for(int i=0;i<=n+1;i++)
    {
        dis1[i]=inf;
        vis[i]=0;
    }
    priority_queue<point>q;
    q.push(point(s,0));
    dis1[s]=0;
    while(!q.empty())
    {
        int rt=q.top().id;
        q.pop();
        if(vis[rt])continue;
        vis[rt]=1;
        for(int i=first[rt];~i;i=e[i].next)
        {
            int id=e[i].to;
            if(!vis[id]&&dis1[rt]+e[i].v<dis1[id])
            {
                dis1[id]=dis1[rt]+e[i].v;
                q.push(point(id,dis1[id]));
            }
        }
    }
}

void dij2(int s)
{
    for(int i=0;i<=n+1;i++)
    {
        dis2[i]=inf;
        vis[i]=0;
    }
    priority_queue<point>q;
    q.push(point(s,0));
    dis2[s]=0;
    while(!q.empty())
    {
        int rt=q.top().id;
        q.pop();
        if(vis[rt])continue;
        vis[rt]=1;
        for(int i=first2[rt];~i;i=re[i].next)
        {
            int id=re[i].to;
            if(!vis[id]&&dis2[rt]+re[i].v<dis2[id])
            {
                dis2[id]=dis2[rt]+re[i].v;
                q.push(point(id,dis2[id]));
            }
        }
    }
}

int main()
{
    ms(first,-1);
    ms(first2,-1);
    scanf("%d%d%d",&n,&m,&x);
    for(int i=1;i<=m;i++)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);
    }
    dij1(x);
    dij2(x);
    int maxx=0;
    for(int i=1;i<=n;i++)
    {
        if(dis2[i]!=inf&&dis2[i]!=inf)
            maxx=max(maxx,dis1[i]+dis2[i]);
    }
    printf("%d\n",maxx);
    return 0;
}
;

E - Currency Exchange& I - Arbitrage

这两题的思路差不多所以放在一起了 算是一种套路的题吧

题目思路

题目都是要找一个正权回路
因为数据大的时候 弗洛伊德用不了
就都用的是spfa
在跑最短路的时候加一个记录次数的数组
如果某一个结点跑到的次数超过了n次
那么这个节点一定在一个环上

//e题代码
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <string.h>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <utility>
#define pi 3.1415926535898
#define ll long long
#define lson rt<<1
#define rson rt<<1|1
#define eps 1e-6
#define ms(a,b) memset(a,b,sizeof(a))
#define legal(a,b) a&b
#define print1 printf("111\n")
using namespace std;
const int maxn = 300+10;
const int inf = 0x3f3f3f3f;
const ll llinf =0x3f3f3f3f3f3f3f3f;
const int mod = 2333;

int first[maxn],vis[maxn],f[maxn],len;
double dis[maxn];
struct node
{
    int to,next;
    double r,c;
}e[maxn<<1];
int n,m,s;
double g;

void add(int u,int v,double r,double c)
{
    e[len].to=v;
    e[len].r=r;
    e[len].c=c;
    e[len].next=first[u];
    first[u]=len++;
}

bool spfa()
{
    for(int i=0;i<=n+1;i++)
    {
        dis[i]=0;
        vis[i]=0;
        f[i]=0;
    }
    dis[s]=g;
    vis[s]=1;
    f[s]++;
    queue<int>q;
    q.push(s);
    int rt;
    while(!q.empty())
    {
        rt=q.front();
        q.pop();
        vis[rt]=0;
        for(int i=first[rt];i!=-1;i=e[i].next)
        {
            int v=e[i].to;
            double tem=(dis[rt]-e[i].c)*e[i].r;
            if(dis[v]<tem)
            {
                dis[v]=tem;
                if(!vis[v])
                {
                    vis[v]=1;
                    f[v]++;
                    q.push(v);
                    if(f[v]>n)
                        return 1;
                }
            }
        }
    }
    if(dis[s]>g)return 1;
    else return 0;
}

int main()
{
    ms(first,-1);
    scanf("%d%d%d%lf",&n,&m,&s,&g);
    for(int i=1;i<=m;i++)
    {
        int a,b;
        double r1,c1,r2,c2;
        scanf("%d%d%lf%lf%lf%lf",&a,&b,&r1,&c1,&r2,&c2);
        add(a,b,r1,c1);
        add(b,a,r2,c2);
    }
    if(spfa())
        printf("YES\n");
    else
        printf("NO\n");

}
//i题代码
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <string.h>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <utility>
#define pi 3.1415926535898
#define ll long long
#define lson rt<<1
#define rson rt<<1|1
#define eps 1e-6
#define ms(a,b) memset(a,b,sizeof(a))
#define legal(a,b) a&b
#define print1 printf("111\n")
using namespace std;
const int maxn = 1e5+10;
const int inf = 0x3f3f3f3f;
const ll llinf =0x3f3f3f3f3f3f3f3f;
const int mod = 2333;

int n,first[maxn],len,f[maxn],vis[maxn];
double dis[maxn];
string str;
map<string,int>mp;

struct node
{
    int to,next;
    double z;
}e[maxn];

void add(int x,int y,double z)
{
    e[len].to=y;
    e[len].z=z;
    e[len].next=first[x];
    first[x]=len++;
}

bool spfa()
{
    for(int i=1;i<=n;i++)
    {
        dis[i]=0;
        vis[i]=0;
        f[i]=0;
    }
    dis[1]=1;
    vis[1]=1;
    f[1]++;
    queue<int>q;
    q.push(1);
    //print1;
    while(!q.empty())
    {
        int id=q.front();
        q.pop();
        vis[id]=0;
        for(int i=first[id];i!=-1;i=e[i].next)
        {
            int v=e[i].to;
            double tem=dis[id]*e[i].z;
            if(tem>dis[v])
            {
                dis[v]=tem;
                if(!vis[v])
                {
                    vis[v]=1;
                    f[v]++;
                    q.push(v);
                    if(f[v]>n)
                    {
                        //print1;
                        return 1;
                    }
                }
            }
        }
    }
    if(dis[1]>1)
        return 1;
    else
        return 0;
}
int main()
{
    int ce=1;
    while(scanf("%d",&n)&&n!=0)
    {
        ms(first,-1);
        mp.clear();
        len=0;
        int cnt=1;
        for(int i=1;i<=n;i++)
        {
            cin>>str;
            mp[str]=cnt++;
        }
        int q;
        scanf("%d",&q);
        while(q--)
        {
            int x,y;
            double z;
            cin>>str;
            x=mp[str];
            //printf("ca %d ",x);
            cin>>z>>str;
            y=mp[str];
            //printf("%d\n",y);
            add(x,y,z);
        }
        printf("Case %d: ",ce++);
        if((spfa()))printf("Yes\n");
        else printf("No\n");
   }

} 

F - Wormholes

跟上面两题差不多 都是查环
不过这题要查的是负环
但套路都差不多 就是换一些比较的东西

ac代码

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <string.h>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <utility>
#define pi 3.1415926535898
#define ll long long
#define lson rt<<1
#define rson rt<<1|1
#define eps 1e-6
#define ms(a,b) memset(a,b,sizeof(a))
#define legal(a,b) a&b
#define print1 printf("111\n")
using namespace std;
const int maxn = 1e4+10;
const int inf = 0x3f3f3f3f;
const ll llinf =0x3f3f3f3f3f3f3f3f;
const int mod = 2333;

int first[maxn],len,vis[maxn],dis[maxn],f[maxn];
int n,m,w;
struct node
{
    int to,next;
    int v;
}e[maxn<<1];

void add(int u,int v,int w)
{
    e[len].to=v;
    e[len].next=first[u];
    e[len].v=w;
    first[u]=len++;
}

bool spfa(int s)
{
    for(int i=0;i<=n+1;i++)
    {
        dis[i]=inf;
        vis[i]=0;
        f[i]=0;
    }
    dis[s]=0;
    vis[s]=1;
    f[s]++;
    queue<int>q;
    q.push(s);
    while(!q.empty())
    {
        int rt=q.front();
        q.pop();
        vis[rt]=0;
        for(int i=first[rt];i!=-1;i=e[i].next)
        {
            int v=e[i].to;
            if(dis[v]>dis[rt]+e[i].v)
            {
                dis[v]=dis[rt]+e[i].v;
                if(!vis[v])
                {
                    vis[v]=1;
                    f[v]++;
                    if(f[v]>n)
                        return 1;
                    q.push(v);
                }
            }
        }
    }
    return 0;
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        ms(first,-1);
        len=0;
        scanf("%d%d%d",&n,&m,&w);
        for(int i=1;i<=m;i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z);
            add(y,x,z);
        }
        for(int i=1;i<=w;i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z*(-1));
        }
        if(spfa(1))
            printf("YES\n");
        else
            printf("NO\n");

    }

}

H - Cow Contest

又是看了题解才晓得咋写的题

题目思路

题目给出了两个牛之间的关系
可以抽象成一条边
若a赢了b 就记录成mp[a][b]=1 mp[b][a]=-1
因为题目数据小于1e3 所以直接跑弗洛伊德就行
判断的时候如果mp[i][k]==mp[k][j]并且他们都不等于inf
那么i j至今的关系就能确定了 这个关系可以自己理一下
然后在遍历每一个数与其他数之间的关系是否都能确定
如果可以ans++

ac代码

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <string.h>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <utility>
#define pi 3.1415926535898
#define ll long long
#define lson rt<<1
#define rson rt<<1|1
#define eps 1e-6
#define ms(a,b) memset(a,b,sizeof(a))
#define legal(a,b) a&b
#define print1 printf("111\n")
using namespace std;
const int maxn = 1e4+10;
const int inf = 0x3f3f3f3f;
const ll llinf =0x3f3f3f3f3f3f3f3f;
const int mod = 2333;

int mp[105][105];

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    ms(mp,inf);
    for(int i=1;i<=n;i++)
        mp[i][i]=0;
    for(int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        mp[x][y]=1;
        mp[y][x]=-1;
    }
    for(int k=1;k<=n;k++)
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(mp[i][k]==mp[k][j]&&mp[i][k]!=inf)
                    mp[i][j]=mp[i][k];
            }
        }
    }
    int cnt=0;
    for(int i=1;i<=n;i++)
    {
        int flag=0;
        for(int j=1;j<=n;j++)
        {
            if(mp[i][j]==inf)
                flag=1;
        }
        if(flag==0)
            cnt++;
    }
    printf("%d\n",cnt);
}

J - Invitation Cards

题目思路

与d题类似 建两遍图 跑两次最短路
在把所有的值加起来
记得开ll

ac代码

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <string.h>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <utility>
#define pi 3.1415926535898
#define ll long long
#define lson rt<<1
#define rson rt<<1|1
#define eps 1e-6
#define ms(a,b) memset(a,b,sizeof(a))
#define legal(a,b) a&b
#define print1 printf("111\n")
using namespace std;
const int maxn = 1e6+10;
const int inf = 0x3f3f3f3f;
const ll llinf =0x3f3f3f3f3f3f3f3f;
const int mod = 2333;

struct node
{
    int to,next,v;
}e[maxn<<1],re[maxn<<1];
int len1,len2;
int n,m;
int first[maxn],first2[maxn],vis[maxn];
ll dis1[maxn],dis2[maxn];

void add(int u,int v,int w)
{
    e[len1].to=v;
    e[len1].next=first[u];
    e[len1].v=w;
    first[u]=len1++;
    re[len2].to=u;
    re[len2].next=first2[v];
    re[len2].v=w;
    first2[v]=len2++;
}

struct point
{
    int id;
    ll val;
    point(int id,ll val)
    {
        this->id=id;
        this->val=val;
    }
    bool operator <(const point&x)const
    {
        return val>x.val;
    }
};

void dij1(int s)
{
    for(int i=0;i<=n+1;i++)
    {
        vis[i]=0;
        dis1[i]=llinf;
    }
    priority_queue<point>q;
    q.push(point(s,0));
    dis1[s]=0;
    while(!q.empty())
    {
        int rt=q.top().id;
        q.pop();
        if(vis[rt])continue;
        vis[rt]=1;
        for(int i=first[rt];i!=-1;i=e[i].next)
        {
            int id=e[i].to;
            if(!vis[id]&&dis1[rt]+e[i].v<dis1[id])
            {
                dis1[id]=dis1[rt]+e[i].v;
                q.push(point(id,dis1[id]));
            }
        }
    }
}

void dij2(int s)
{
    for(int i=0;i<=n+1;i++)
    {
        vis[i]=0;
        dis2[i]=llinf;
    }
    priority_queue<point>q;
    q.push(point(s,0));
    dis2[s]=0;
    while(!q.empty())
    {
        int rt=q.top().id;
        q.pop();
        if(vis[rt])continue;
        vis[rt]=1;
        for(int i=first2[rt];i!=-1;i=re[i].next)
        {
            int id=re[i].to;
            if(!vis[id]&&dis2[rt]+re[i].v<dis2[id])
            {
                dis2[id]=dis2[rt]+re[i].v;
                q.push(point(id,dis2[id]));
            }
        }
    }
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        ms(first,-1);
        ms(first2,-1);
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            int x,y,v;
            scanf("%d%d%d",&x,&y,&v);
            add(x,y,v);
        }
        dij1(1);
        dij2(1);
        ll sum=0;
        for(int i=2;i<=n;i++)
        {
            sum+=dis1[i]+dis2[i];
        }
        printf("%lld\n",sum);
    }
}

N - Tram

题目思路

与上面h题建图方式有些类似
将每条路第一个连着的设为0
其余要该方向才能走的路设为1
跑最短路就好了
因为数据比较小
直接弗洛伊德就行了
记得把mp[i][i]初始化为0

ac代码

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <string.h>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <utility>
#define pi 3.1415926535898
#define ll long long
#define lson rt<<1
#define rson rt<<1|1
#define eps 1e-6
#define ms(a,b) memset(a,b,sizeof(a))
#define legal(a,b) a&b
#define print1 printf("111\n")
using namespace std;
const int maxn = 1e6+10;
const int inf = 0x3f3f3f3f;
const ll llinf =0x3f3f3f3f3f3f3f3f;
const int mod = 2333;

int n,a,b;
int mp[105][105];


int main()
{
    scanf("%d%d%d",&n,&a,&b);
    ms(mp,inf);
    for(int i=1;i<=n;i++)
    {
        int k;
        scanf("%d",&k);
        for(int j=1;j<=k;j++)
        {
            int x;
            scanf("%d",&x);
            if(j==1)
                mp[i][x]=0;
            else
                mp[i][x]=1;
        }
    }
    for(int i=1;i<=n;i++)
        mp[i][i]=0;
    for(int k=1;k<=n;k++)
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                //printf("%d %d %d %d\n",k,i,j,mp[i][j]);
                mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
                //printf("%d %d %d %d\n",k,i,j,mp[i][j]);
            }
        }
    }
    if(mp[a][b]!=inf)
        printf("%d\n",mp[a][b]);
    else
        printf("-1\n");
}

K - Candies

题目思路

差分约束的题意 抽象之后建图跑最短路就好了
知道怎么建图 这题解释个最短路裸题了

ac代码

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <string.h>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <utility>
#define pi 3.1415926535898
#define ll long long
#define lson rt<<1
#define rson rt<<1|1
#define eps 1e-6
#define ms(a,b) memset(a,b,sizeof(a))
#define legal(a,b) a&b
#define print1 printf("111\n")
using namespace std;
const int maxn = 2e5+10;
const int inf = 0x3f3f3f3f;
const ll llinf =0x3f3f3f3f3f3f3f3f;
const int mod = 2333;

int first[maxn],vis[maxn];
int dis[maxn],len;
int n,m;
struct node
{
    int to,next;
    int v;
}e[maxn<<1];

void add(int u,int v,int w)
{
    e[len].to=v;
    e[len].v=w;
    e[len].next=first[u];
    first[u]=len++;
}

struct point
{
    int id;
    ll val;
    point(int id,ll val)
    {
        this->id=id;
        this->val=val;
    }
    bool operator<(const point &x)const
    {
        return val>x.val;
    }
};

void dij(int s)
{
    for(int i=0;i<=n+1;i++)
    {
        dis[i]=inf;
        vis[i]=0;
    }
    priority_queue<point>q;
    q.push(point(s,0));
    dis[s]=0;
    while(!q.empty())
    {
        int rt=q.top().id;
        q.pop();
        if(vis[rt])continue;
        vis[rt]=1;
        for(int i=first[rt];i!=-1;i=e[i].next)
        {
            int id=e[i].to;
            if(!vis[id]&&dis[rt]+e[i].v<dis[id])
            {
                dis[id]=dis[rt]+e[i].v;
                q.push(point(id,dis[id]));
            }
        }
    }
}
int main()
{
    ms(first,-1);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x,y,v;
        scanf("%d%d%d",&x,&y,&v);
        add(x,y,v);
    }
    dij(1);
    int maxx=0;
    for(int i=1;i<=n;i++)
    {
        if(dis[i]!=inf)
            maxx=max(dis[i],maxx);
    }
    printf("%d\n",maxx);
}

G - MPI Maelstrom

题目思路

题目用类似矩阵的方式给出边权值 直接建图跑最短路 求最大路径就好
唯一的难点就是输入会有x
所以应该是输入字符型而不是整型
开始觉得字符型再转整型挺麻烦的
看了题解说直接用atoi这个函数来把字符串数组转变成整型
又学到了新东西

ac代码

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <string.h>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <utility>
#define pi 3.1415926535898
#define ll long long
#define lson rt<<1
#define rson rt<<1|1
#define eps 1e-6
#define ms(a,b) memset(a,b,sizeof(a))
#define legal(a,b) a&b
#define print1 printf("111\n")
using namespace std;
const int maxn = 2e5+10;
const int inf = 0x3f3f3f3f;
const ll llinf =0x3f3f3f3f3f3f3f3f;
const int mod = 2333;

ll dis[maxn];
int vis[maxn],first[maxn],len;
int n;
struct node
{
    int to,next,v;
}e[maxn<<1];

void add(int u,int v,int w)
{
    e[len].to=v;
    e[len].v=w;
    e[len].next=first[u];
    first[u]=len++;
}

struct point
{
    int id;
    ll val;
    point(int id,ll val)
    {
        this->id=id;
        this->val=val;
    }
    bool operator<(const point &x)const
    {
        return val>x.val;
    }
};

void dij(int s)
{
    for(int i=0;i<=n+1;i++)
    {
        dis[i]=llinf;
        vis[i]=0;
    }
    priority_queue<point>q;
    q.push(point(s,0));
    dis[s]=0;
    //print1;
    while(!q.empty())
    {
        int rt=q.top().id;
        q.pop();
        if(vis[rt])continue;
        for(int i=first[rt];i!=-1;i=e[i].next)
        {
            int id=e[i].to;
            if(!vis[id]&&dis[rt]+e[i].v<dis[id])
            {
                dis[id]=dis[rt]+e[i].v;
                q.push(point(id,dis[id]));
            }
        }
    }

}
int main()
{
    ms(first,-1);
    scanf("%d",&n);
    for(int i=2;i<=n;i++)
    {
        for(int j=1;j<i;j++)
        {
            char x[20];
            scanf("%s",x);
            if(x[0]!='x')
            {
                int w=atoi(x);
                add(i,j,w);
                add(j,i,w);
            }
        }
    }
    dij(1);
    ll maxx=0;
    for(int i=1;i<=n;i++)
        if(dis[i]!=llinf)
            maxx=max(maxx,dis[i]);
    printf("%lld\n",maxx);
}

昨天的自闭多校 摸了一下午鱼 过了几道简单题之后
困得不行 写题目也写不进
晚上整个就处于一种快要死掉的状态
看了下题目 一脸懵逼得过了s题
说实话对差分约束还是挺懵逼得

S - Layout

题目思路

其实挺容易看出来是差分约束的
有两种情况
x-y>=z
a-b<=c
第一种情况就是我们跑最短路建图是需要的样子
第二种情况我们其实也能变成第一种
直接成一个-1
式子就变成了
b-a>=-c 这样就能一起建图了
但是这样也让图里面可能又负环
所以要送spfa跑最短路得同时 判断是否有负环有的话就退出
最后的输出要注意 之前就没搞清楚
负环是使得无法跑到终点 所以没有答案 应该输出-1
最后的值等于inf则是说两点不连通 所以他们的距离可以为任意距离
所以输出-2

ac代码

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <string.h>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <utility>
#define pi 3.1415926535898
#define ll long long
#define lson rt<<1
#define rson rt<<1|1
#define eps 1e-6
#define ms(a,b) memset(a,b,sizeof(a))
#define legal(a,b) a&b
#define print1 printf("111\n")
using namespace std;
const int maxn = 1e6+10;
const int inf = 0x3f3f3f3f;
const ll llinf =0x3f3f3f3f3f3f3f3f;
const int mod = 2333;

struct node
{
    int to,next;
    ll v;
}e[maxn];
int first[maxn],vis[maxn],f[maxn],len;
ll dis[maxn];
int n,ml,mr;

void add(int u,int v,int w)
{
    e[len].to=v;
    e[len].next=first[u];
    e[len].v=w;
    first[u]=len++;
}

void spfa(int st)
{
    for(int i=0;i<=n+1;i++)
    {
        dis[i]=llinf;
        vis[i]=0;
        f[i]=0;
    }
    dis[st]=0;
    vis[st]=1;
    f[st]++;
    int flag=0;
    queue<int>q;
    q.push(st);
    while(!q.empty())
    {
        st=q.front();
        q.pop();
        vis[st]=0;
        for(int i=first[st];i!=-1;i=e[i].next)
        {
            int id=e[i].to;
            if(dis[id]>dis[st]+e[i].v)
            {
                dis[id]=dis[st]+e[i].v;
                if(!vis[id])
                {
                    f[id]++;
                    vis[id]=1;
                    if(f[id]>n)
                    {
                        flag=2;
                        break;
                    }
                    q.push(id);
                }

            }
        }
    }
    if(flag==2)
        printf("-1\n");
    else if(dis[n]==llinf)
        printf("-2\n");
    else
        printf("%lld\n",dis[n]);
}

int main()
{

    scanf("%d%d%d",&n,&ml,&mr);
    len=0;
    ms(first,-1);
    for(int i=1;i<=ml;i++)
    {
        int x,y;
        ll z;
        scanf("%d%d%lld",&x,&y,&z);
        add(x,y,z);
    }
    for(int i=1;i<=mr;i++)
    {
        int x,y;
        ll z;
        scanf("%d%d%lld",&x,&y,&z);
        add(y,x,(-1)*z);
    }
    spfa(1);
}

P - The Shortest Path in Nya Graph

题目思路

题目给出了一个层的概念
可以根据层建一个 相邻层到点距离为c 自己在的层的点和自己的距离为0
这样建图跑最短路 还要就是自己在的层到自己的边只建一个单向边
其他的记得见双向的

ac代码

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <string.h>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <utility>
#define pi 3.1415926535898
#define ll long long
#define lson rt<<1
#define rson rt<<1|1
#define eps 1e-6
#define ms(a,b) memset(a,b,sizeof(a))
#define legal(a,b) a&b
#define print1 printf("111\n")
using namespace std;
const int maxn = 5e5+10;
const int inf = 0x3f3f3f3f;
const ll llinf =0x3f3f3f3f3f3f3f3f;
const int mod = 2333;

int n,m;
ll c;
int len;
int first[maxn],vis[maxn];
ll dis[maxn];

struct node
{
    int to,next,v;
}e[maxn<<1];

void add(int u,int v,int w)
{
    e[len].to=v;
    e[len].v=w;
    e[len].next=first[u];
    first[u]=len++;
}

struct point
{
    int id;
    ll val;
    point(int id,ll val)
    {
        this->id=id;
        this->val=val;
    }
    bool operator<(const point &x)const
    {
        return val>x.val;
    }
};

void dij(int s)
{
    for(int i=1;i<=maxn;i++)
        dis[i]=llinf;
    ms(vis,0);
    priority_queue<point>q;
    q.push(point(s,0));
    dis[s]=0;
    while(!q.empty())
    {
        int rt=q.top().id;
        q.pop();
        if(vis[rt])continue;
        vis[rt]=1;
        if(rt==n)return;
        for(int i=first[rt];i!=-1;i=e[i].next)
        {
            int id=e[i].to;
            if(!vis[id]&&dis[rt]+e[i].v<dis[id])
            {
                dis[id]=dis[rt]+e[i].v;
                q.push(point(id,dis[id]));
            }
        }
    }
}

int main()
{
    int t,ce=1;
    scanf("%d",&t);
    while(t--)
    {
        ms(first,-1);
        scanf("%d%d%lld",&n,&m,&c);
        len=0;
        for(int i=1;i<=n;i++)
        {
            int l;
            scanf("%d",&l);
            //add(i,l+n,0);
            add(l+n,i,0);
            if(l-1>0)
            {
                add(i,l+n-1,c);
                add(l+n-1,i,c);
            }
            add(i,l+n+1,c);
            add(l+n+1,i,c);
        }

        for(int i=1;i<=m;i++)
        {
            int x,y;
            ll z;
            scanf("%d%d%lld",&x,&y,&z);
            add(x,y,z);
            add(y,x,z);
        }
        dij(1);
        printf("Case #%d: ",ce++);
        if(dis[n]==llinf)
            printf("-1\n");
        else
            printf("%lld\n",dis[n]);
    }
}

更完这一题最短路专题就差不多结束了 其实还有几题没写
但是新的字典树的专题又来了 图论的也没写多少
要把这些也补补 准备一下选拔赛了 虽然应该是垫底
但是希望不要差太多

你可能感兴趣的:(最短路专题)