最短路

今天决定刷图论了,做到至少比赛的时候图论的题能够写出来。。。

POJ-1062-昂贵的聘礼

Dijkstra即可。。

因为这题可以抽象出边上有权值,点上也有权值。。我们可以先忽略点上的权值,用Dijkstra算出1~n的最短路,最后再加上点上的权值,然后求所有点的最小值即可。。否则把点上的权值也带入求最小值,会wa。。。我被wa了N次了。。。

这题有等级制度,故需要枚举区间进行多次最短路。
最短路最短路View Code

#include <cstdio>
#include <cstring>
#include <iostream>
#define MAXN 105
#define MM 100000000
using namespace std;

int g[MAXN][MAXN];
int v[MAXN];
int d[MAXN];
int vis[MAXN];
int rank[MAXN];

int dis(int n,int m,int a,int b)
{
    int ans=v[1];
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++)
        d[i]=MM;
    d[1]=0;
    for(int i=1;i<=n;i++)
    {
        if(g[1][i]&&rank[i]<=b&&rank[i]>=a)
        {
            d[i]=g[1][i];
        }
    }
    vis[1]=1;
    for(int i=1;i<=n;i++)
    {
        int minn=MM;
        int k=0;
        for(int j=1;j<=n;j++)
        {
            if(d[j]<minn&&!vis[j])
            {
                minn=d[j];
                k=j;
            }
        }
        vis[k]=1;
        if(k==0)
            break;
    //        return ans;
    //    ans=min(ans,d[k]);
        for(int j=1;j<=n;j++)
        {
            if(g[k][j]&&!vis[j]&&rank[j]<=b&&rank[j]>=a&&d[k]+g[k][j]<d[j])
                d[j]=d[k]+g[k][j];
        }
    }
    for(int i=1;i<=n;i++)
        ans=min(ans,d[i]+v[i]);
    return ans;
}
int main(){
    int n,m;
    while(scanf("%d%d",&m,&n)==2)
    {
        memset(g,0,sizeof(g));
        int k;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d%d",&v[i],&rank[i],&k);
            for(int j=1;j<=k;j++)
            {
                int a,b;
                scanf("%d%d",&a,&b);
                g[i][a]=b;
            }
        }
        int ans=v[1];
        for(int i=rank[1]-m;i<=rank[1];i++)//枚举区间
        {
            ans=min(dis(n,m,i,i+m),ans);
        }
        printf("%dn",ans);
    }

    return 0;
}

POJ-1502 MPI Maelstrom

这题是求所有最短路中的最大值。。用dijkstra即可
最短路最短路View Code

#include <cstdio>
#include <cstring>
#include <iostream>
#define MM 1000000000
#define MAXN 105
using namespace std;
int g[MAXN][MAXN];
int d[MAXN],vis[MAXN];

int dis(int s,int n)
{
    int ans=0;
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++)
    {
        d[i]=g[1][i];
    }
    vis[1]=1;
    for(int i=1;i<=n;i++)
    {
        int minc=MM,k=0;
        for(int j=1;j<=n;j++)
        {
            if(d[j]<minc&&!vis[j])
            {
                minc=d[j];k=j;
            }
        }
        if(k==0)
        //    return ans;
        break;
        vis[k]=1;
        //ans+=d[k];
        ans=max(ans,minc);
        for(int j=1;j<=n;j++)
        {
            if(g[k][j]+d[k]<d[j]&&!vis[j])
                d[j]=g[k][j]+d[k];
        }
    //    return ans;
    }

    return ans;
}

int main()
{
    int n;
    scanf("%d",&n);
    char ch[100];
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(i==j)
                g[i][j]=0;
            else
                g[i][j]=MM;
    for(int i=2;i<=n;i++)
    {
        for(int j=1;j<i;j++)
        {
            scanf("%s",ch);
            if(ch[0]=='x')
                continue;
            int s=0;
            int len=strlen(ch);
            for(int k=0;k<len;k++)
                s=s*10+ch[k]-'0';
        //    scanf("%d",&g[i][j]);
            g[j][i]=g[i][j]=s;
        //    printf("%d %d %dn",i,j,s);
        }
    }
    printf("%dn",dis(1,n));
}

POJ-2387-Til the Cows Come Home

这题目要注意重边。。。dij算法要考虑重边

啊啊啊,以后做图论题得先把特殊情况都先考虑好啊啊。。
最短路最短路View Code

#include <cstdio>
#include <cstring>
#include <iostream>
#define MAXN 1005
#define INF 1000000000
using namespace std;
int g[MAXN][MAXN];
int vis[MAXN],d[MAXN];
int T,N;
int dij(int s,int end)
{
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=N;i++)
        if(g[s][i])
            d[i]=g[s][i];
        else d[i]=INF;
        d[s]=0;
    for(int i=1;i<=N;i++)
    {
        int minc=INF,k=0;
        for(int j=1;j<=N;j++)
            if(d[j]<minc&&!vis[j])
            {
                minc=d[j];k=j;
            }
        if(k==0)
            break;
        vis[k]=1;
        if(k==end)
            return d[k];
        for(int j=1;j<=N;j++)
            if(!vis[j]&&d[j]>d[k]+g[k][j]&&g[k][j])
                d[j]=d[k]+g[k][j];
    }
    return d[end];
}
int main()
{

    scanf("%d%d",&T,&N);
    int a,b,c;
    memset(g,0,sizeof(g));
    for(int i=1;i<=T;i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        if(g[a][b])
            g[a][b]=g[b][a]=min(g[a][b],c);
        else
        g[a][b]=g[b][a]=c;
    }
    printf("%dn",dij(N,1));
}

POJ-3268-Silver Cow Party

这题还好,挺好做的,只是需要转换一点罢了,用dij
最短路最短路View Code

#include <cstdio>
#include <cstring>
#include <iostream>
#define INF 1000000000
#define MAXN 1005
using namespace std;
int g[MAXN][MAXN];
int N,M,X;
int gg[MAXN][MAXN];
int vis[MAXN],d[MAXN];
int ans[MAXN];
void dis(int s,int m[MAXN][MAXN])
{
    for(int i=1;i<=N;i++)
        if(m[s][i])
        d[i]=m[s][i];
        else d[i]=INF;
    d[s]=0;
    memset(vis,0,sizeof(vis));
    vis[s]=1;
    for(int i=1;i<=N;i++)
    {
        int minc=INF,k=0;
        for(int j=1;j<=N;j++)
        {
            if(!vis[j]&&d[j]<minc)
            {
                minc=d[j];k=j;
            }
        }
        if(k==0)
            break;
        vis[k]=1;
        for(int j=1;j<=N;j++)
        {
            if(!vis[j]&&d[j]>d[k]+m[k][j]&&m[k][j])
                d[j]=d[k]+m[k][j];
        }
    }
    for(int i=1;i<=N;i++)
        ans[i]+=d[i];
}
int main()
{
    int a,b,t;
    scanf("%d%d%d",&N,&M,&X);
    memset(g,0,sizeof(g));
    memset(gg,0,sizeof(gg));
    memset(ans,0,sizeof(ans));
    for(int i=1;i<=M;i++)
    {
        scanf("%d%d%d",&a,&b,&t);
        g[a][b]=gg[b][a]=t;
    }
    dis(X,g);
    dis(X,gg);
    int maxn=0;
    for(int i=1;i<=N;i++)
        maxn=max(ans[i],maxn);
    printf("%dn",maxn);
}

POJ-1511-Invitation Cards

题意:在一个城市里,有n(1~1000000)个运输中心,有m条有向路连接着任意的两个运输中心。ACM组织(位于编号为1的运输中心)要派发p个雇佣员工早上前往这p个运输中心去发传单,晚上再让他们都回到组织中。问所有人所走路程的总和最短是多少?

因为是稀疏图,所以用邻接表,所以用spfa算法。输入的时候存两个图,一个是原图,一个是原图的每条边都反向的图。。这样求两次spfa从一点到其他所有点的距离即可。
最短路最短路View Code

#include <cstdio>
#include <cstring>
#include <iostream>
#define MAXN 1000050
#define INF 1000000000

using namespace std;

struct node{
    int v,w,next;
}edge1[MAXN];
node edge2[MAXN];
int first1[MAXN],first2[MAXN];
long long d[MAXN];
int q[MAXN],vis[MAXN];
int P,Q;
int e1,e2;
void init(int n)
{
    memset(first1,-1,sizeof(first1));
    memset(first2,-1,sizeof(first2));
    e1=0,e2=0;
}
void add1(int u,int v,int w)
{
    edge1[e1].v=v;
    edge1[e1].w=w;
    edge1[e1].next=first1[u];
    first1[u]=e1++;
}
void add2(int u,int v,int w)
{
    edge2[e2].v=v;
    edge2[e2].w=w;
    edge2[e2].next=first2[u];
    first2[u]=e2++;
}
long long spfa(int s,node *edge,int *first)
{
    long long ans=0;
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=P;i++)
        d[i]=INF;
    d[s]=0;
    int rear=0,front=0;
    q[rear++]=s;
    while(rear!=front)
    {
        int u=q[front++];
        if(front>P)
            front=0;
        vis[u]=0;
        for(int i=first[u];i!=-1;i=edge[i].next)
        {
            int v=edge[i].v;
            if(d[v]>d[u]+edge[i].w)
            {
                d[v]=d[u]+edge[i].w;
                if(!vis[v])
                {
                    vis[v]=1;
                    q[rear++]=v;
                    if(rear>P)
                        rear=0;
                }
            }
        }
    }
    for(int i=1;i<=P;i++)
        ans+=d[i];
    return ans;
}
int main()
{
    int tt;
    scanf("%d",&tt);
    while(tt--)
    {
        int a,b,c;
        scanf("%d%d",&P,&Q);
        init(P);
        for(int i=1;i<=Q;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            add1(a,b,c);
            add2(b,a,c);
        }
        long long ans=0;
        ans+=spfa(1,edge1,first1);
        ans+=spfa(1,edge2,first2);
        cout<<ans<<endl;
    }
}

POJ-1724-ROADS

题意:Bob现在有的钱数为coin,他想从城市1到城市n,给出m条连接两个城市的有向边,并且给出路的长度w,和经过这条路要交的钱数c。问Bol能从1到达城市n的最短路径为多长。(总共扣的钱数必须不大于coin)

分析:改普通的dij为:只要一边起点的当前花费钱数 + 这条边的花费钱数 <= coin,就让这边终点的信息加入优先队列.(普通的dij是终边的距离有变小才让其加入优先队列)

这题的dij还用到了邻接表。其实这完全可以看做BFS+优先队列
最短路最短路View Code

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

#define MAXN 10050
using namespace std;
struct ee{
    int v,w,c,next;
}edge[MAXN];
struct node{
    int u,l,c;
    bool operator <(const node &a)const{
        return l>a.l;
    };
};
int first[105];
priority_queue<node> q;
int K,N,R;
int e;

void init(int n)
{
    memset(first,-1,sizeof(first));
    e=0;
}
void add(int u,int v,int w,int c)
{
    edge[e].v=v;
    edge[e].w=w;
    edge[e].c=c;
    edge[e].next=first[u];
    first[u]=e++;
}
int dij(int s,int end)
{
    while(!q.empty())
    {
        q.pop();
    }
    node a;
    a.u=s,a.l=0,a.c=0;
    q.push(a);
    while(!q.empty())
    {
        node now=q.top();
        q.pop();
        int u=now.u;
        if(u==end)return now.l;
        for(int i=first[u];i!=-1;i=edge[i].next)
        {
            int v=edge[i].v;
            if(now.c+edge[i].c<=K)
            {
                a.u=v,a.l=now.l+edge[i].w,a.c=now.c+edge[i].c;
                q.push(a);
            }

        }
    }
    return -1;
}
int main()
{
    scanf("%d%d%d",&K,&N,&R);
    int s,d,l,t;
    init(N);
    for(int i=0;i<R;i++)
    {
        scanf("%d%d%d%d",&s,&d,&l,&t);
        add(s,d,l,t);
    }
    printf("%dn",dij(1,N));
}

POJ-1797-Heavy Transportation

题意:求1到n路径权值最小值中的最大值

用变形的dij写,其实这个我之前都是用变形的spfa写的,dij不会写,变形的地方原理一样。。

for(int j=1;j<=n;j++)
            if(!vis[j]&&d[j]<min(d[k],g[k][j]))
                d[j]=min(d[k],g[k][j]);

好吧,贴上变形的dij代码
最短路最短路View Code

#include <cstring>
#include <cstdio>
#include <iostream>

#define MAXN 1005
#define INF 1000000000
using namespace std;
int g[MAXN][MAXN];
int d[MAXN],vis[MAXN];
int n,m;

int dij(int s,int end)
{
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++)
            d[i]=g[s][i];
    vis[s]=1,d[s]=0;
    for(int i=1;i<=n;i++)
    {
        int maxn=0,k=0;
        for(int j=1;j<=n;j++)
            if(d[j]>maxn&&!vis[j])
            {
                maxn=d[j];k=j;
            }
        if(!k)
            break;
        vis[k]=1;
        for(int j=1;j<=n;j++)
            if(!vis[j]&&d[j]<min(d[k],g[k][j]))
                d[j]=min(d[k],g[k][j]);
    }
    return d[n];
}
int main()
{
    int tt;
    scanf("%d",&tt);
    for(int cas=1;cas<=tt;cas++)
    {
        memset(g,0,sizeof(g));
        scanf("%d%d",&n,&m);
        int a,b,c;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            if(g[a][b])
                g[a][b]=g[b][a]=max(c,g[a][b]);
            else g[a][b]=g[b][a]=c;
        }
        printf("Scenario #%d:n",cas);
        printf("%dnn",dij(1,n));
    }
}

POJ-2253-Frogger

题意:

给出两只青蛙的坐标A、B,和其他的n-2个坐标,任一两个坐标点间都是双向连通的。显然从A到B存在至少一条的通路,每一条通路的元素都是这条通路中前后两个点的距离,这些距离中又有一个最大距离。

现在要求求出所有通路的最大距离,并把这些最大距离作比较,把最小的一个最大距离作为青蛙的最小跳远距离。

变形的dij
最短路最短路View Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#define MAXN 205
using namespace std;
double g[MAXN][MAXN];
struct node{
    int x,y;
}p[MAXN];
double d[MAXN];
int vis[MAXN];
int n;
double cul(node a,node b){
    return sqrt(1.0*(a.x-b.x)*(a.x-b.x)+1.0*(a.y-b.y)*(a.y-b.y));
}
double dij(int s,int end){
    for(int i=1;i<=n;i++)
    d[i]=g[s][i];
    memset(vis,0,sizeof(vis));
    vis[s]=1;
    for(int i=1;i<=n;i++){
        double minc=1000000000;
        int k=0;
        for(int j=1;j<=n;j++){
            if(minc>d[j]&&!vis[j])
            {
                minc=d[j],k=j;
            }
        }
        if(k==0)break;
        vis[k]=1;
        for(int j=1;j<=n;j++){
            if(!vis[j]&&(d[j]>max(d[k],g[k][j])))
            d[j]=max(d[k],g[k][j]);
        }
    }
    return d[end];
}
int main()
{
    int cas=1;
    while(scanf("%d",&n)==1){
        if(!n)break;
        int a,b;
        for(int i=1;i<=n;i++){
            scanf("%d%d",&a,&b);
            p[i].x=a,p[i].y=b;
        }
        for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        g[i][j]=1000000000;
        for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        g[i][j]=cul(p[i],p[j]);
        printf("Scenario #%dn",cas++);
        printf("Frog Distance = %.3lfnn",dij(1,2));
    }
    return 0;
}

POJ-2502-Subway

分析:就是求两点之间的最短距离,不过这题的建图麻烦点。。dij水之
最短路最短路View Code

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#define MAXN 205
using namespace std;
double g[MAXN][MAXN];
bool f[MAXN][MAXN];
struct node{
    int x,y;
}p[MAXN];
int n;
double walkv,subv;
double d[MAXN];
int vis[MAXN];
double dis(node a,node b)
{
    return sqrt(1.0*(a.x-b.x)*(a.x-b.x)+1.0*(a.y-b.y)*(a.y-b.y));
}
double dij(int s,int end)
{
    memset(vis,0,sizeof(vis));
    for(int i=0;i<n;i++)
        d[i]=g[s][i];
    vis[s]=1;
    for(int i=0;i<n;i++)
    {
        double minc=1000000000;
        int k=-1;
        for(int j=0;j<n;j++)
            if(!vis[j]&&minc>d[j])
            {
                k=j,minc=d[j];
            }
        if(k==-1)break;
        if(k==end)
            return d[k];
        vis[k]=1;
        for(int j=0;j<n;j++)
            if(!vis[j]&&d[k]+g[k][j]<d[j])
                d[j]=d[k]+g[k][j];
    }
    return d[end];
}
int main()
{
    scanf("%d%d",&p[0].x,&p[0].y);
    scanf("%d%d",&p[1].x,&p[1].y);
    n=2;
    int a,b;
    int m=2;
    subv=40*1000.0/60;
    walkv=10*1000.0/60;
    memset(f,false,sizeof(f));
    while(scanf("%d%d",&a,&b)==2)
    {
        if(a==-1&&b==-1)
        {
            for(int i=m;i<n-1;i++)
            {
                g[i][i+1]=g[i+1][i]=dis(p[i],p[i+1])/subv;
                f[i][i+1]=f[i+1][i]=true;
            }
            m=n;
            continue;
        }
        p[n].x=a,p[n].y=b;
        n++;
    }
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            if(!f[i][j])
                g[i][j]=dis(p[i],p[j])/walkv;
    printf("%dn",(int)(dij(0,1)+0.5));
}

POJ-3013-Big Christmas Tree

分析:每条边的权值=这条边的unit price*这条边的所有子孙节点的和,求一棵树n个节点的(n-1)条边边权之和的最小值。

可以转化为ans = ∑dist[i] * weight[i].(1 <= i <= vn),其中dist[i]为结点i到根结点root(1)的距离,vn为结点数.

这题还有空树的情况。。伤不起啊。。

用SPFA即可
最短路最短路View Code

#include <iostream>
#include <cstdio>
#include <cstring>
#define MAXN 50050
#define LL long long
#define INF 10000000000LL
using namespace std;
struct ee{
    int v,w,next;
}edge[MAXN*3];
int first[MAXN];
int e;
LL d[MAXN];
int vis[MAXN],q[MAXN];
int cnt[MAXN];
int p[MAXN];
int n,m;
void add(int u,int v,int w){
    edge[e].v=v;
    edge[e].w=w;
    edge[e].next=first[u];
    first[u]=e++;
}
LL spfa(int s){
    int front=0,rear=0;
    memset(vis,0,sizeof(vis));
//    memset(cnt,0,sizeof(cnt));
    for(int i=1;i<=n;i++)
    d[i]=INF;
    q[rear++]=s;
    d[s]=0;
    vis[s]=1;
    while(front!=rear){
        int u=q[front++];
        if(front>n)front=0;
        vis[u]=0;
        for(int i=first[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(d[v]>d[u]+edge[i].w){
                d[v]=d[u]+edge[i].w;
                if(!vis[v]){
                    q[rear++]=v;
            //        cnt[v]++;
           //         if(cnt[v]>n)return -1;//这个用来求是否有负环,有,返回-1
                    if(rear>n)rear=0;
                    vis[v]=1;
                }
            }
        }
    }
    LL ans=0;
    for(int i=1;i<=n;i++)
    if(d[i]==INF)return -1;
    else
    ans+=d[i]*p[i];
    return ans;
}
int main()
{
    freopen("in.txt","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        scanf("%d",&p[i]);
        int a,b,c;
        memset(first,-1,sizeof(first));
        e=0;
        for(int i=0;i<m;i++){
            scanf("%d%d%d",&a,&b,&c);
            add(a,b,c);add(b,a,c);
        }
        if(n==0)printf("0n");
        else{
        LL ans=spfa(1);
        if(ans==-1)printf("No Answern");
        else
        printf("%I64dn",ans);
        }
    }
    return 0;
}

POJ-3635-Full Tank?

题意:坐汽车旅游,有n个加油站,每个站有自己的油价,假设每个单位距离耗一个单位油。车子邮箱最多能装c单位油。

问从a到b的最小花费

分析:这题要用到DP状态转移的思想,dp[i][j]表示在i站剩余j单位油时的最小花费,增加状态要一点一点的增加,如果把第i个站的油量1-cap一次性增加,会超时,增加了很多不需要的状态。。

算法:变形的dij
最短路最短路View Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define MAXN 1050
#define INF 1000000000
using namespace std;
struct ee{
    int v,w,next;
}edge[MAXN*10*2];
int e,first[MAXN];
int dp[MAXN][105];//在i位置剩余j单位油时最少花费
int vis[MAXN][105];
struct node{
    int city;//当前城市
    int fuel;//当前油剩余量
    int cost;//当前花费
    bool operator <(const node &a)const{
        return cost>a.cost;
    };
};
int p[MAXN];
priority_queue<node>q;
int n,m;
void add(int u,int v,int w){
    edge[e].v=v;
    edge[e].w=w;
    edge[e].next=first[u];
    first[u]=e++;
}
int dij(int s,int end,int cap){
    memset(vis,0,sizeof(vis));
    for(int i=0;i<n;i++)
    for(int j=0;j<=cap;j++)dp[i][j]=INF;

    while(!q.empty())q.pop();
    node a;
    a.city=s,a.cost=0,a.fuel=0;
    q.push(a);
    dp[s][0]=0;
    vis[s][0]=1;
    while(!q.empty()){
        node now=q.top();
        q.pop();
        int u=now.city;
        if(u==end)return now.cost;
  /*      for(int i=now.fuel+1;i<=cap&&!vis[u][i]&&dp[u][i]>dp[u][i-1]+p[u];i++)
        {
            a.city=now.city;
            a.cost=dp[u][i-1]+p[u];
            dp[u][i]=dp[u][i-1]+p[u];
            a.fuel=i;
            q.push(a);
        }
        */
        int i=now.fuel+1;//只需将油量增一即可,而不是全加上,如上注释代码,全加上会超时,因为增加了许多不需要的状态
        if(i<=cap&&!vis[u][i]&&dp[u][i]>dp[u][i-1]+p[u]){
            a.city=now.city;
            a.cost=dp[u][i-1]+p[u];
            dp[u][i]=dp[u][i-1]+p[u];
            a.fuel=i;
            q.push(a);
        }
        for(i=first[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            int k=now.fuel-edge[i].w;
            if(k>=0&&!vis[v][k]&&dp[v][k]>now.cost){
                dp[v][k]=now.cost;
                a.city=v;
                a.cost=now.cost;
                a.fuel=k;
                q.push(a);
            }
        }
    }
    return -1;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)
    scanf("%d",&p[i]);
    int a,b,c;
    memset(first,-1,sizeof(first));
    e=0;
    for(int i=0;i<m;i++){
        scanf("%d%d%d",&a,&b,&c);
        add(a,b,c);add(b,a,c);
    }
    int tt;
    scanf("%d",&tt);
    while(tt--){
        scanf("%d%d%d",&a,&b,&c);
        int ans=dij(b,c,a);
        if(ans==-1)printf("impossiblen");
        else printf("%dn",ans);
    }
    return 0;
}

POJ-3621-Sightseeing Cows

http://blog.sina.com.cn/s/blog_69a101130100jwci.html这个解题报告很好

这题要用c++,用G++会wa

题意:求一个环,环中每点都有一个fun值,还有路上所花时间,求环中所有fun值和/遍历环的时间的最大值

分析:通过二分答案,判断负环,求得答案
最短路最短路View Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#define MAXN 5050
#define INF 1000000000
using namespace std;
struct ee{
    int v,w,next;
}edge[MAXN];
int p[MAXN];
int first[MAXN];
int e;
double d[MAXN];
int vis[MAXN],q[MAXN],cnt[MAXN];
int L,P;
void add(int u,int v,int w){
    edge[e].v=v;
    edge[e].w=w;
    edge[e].next=first[u];
    first[u]=e++;
}
bool spfa(double ans){
    int front=0,rear=0;
    memset(vis,0,sizeof(vis));
    memset(cnt,0,sizeof(cnt));
    for(int i=1;i<=L;i++)
    d[i]=INF;
    d[1]=0;
    q[rear++]=1;
    vis[1]=1;
    while(rear!=front){
        int u=q[front++];
        if(front>L)front=0;
        vis[u]=0;
        for(int i=first[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(d[v]>d[u]+edge[i].w*ans-p[v]){
                d[v]=d[u]+edge[i].w*ans-p[v];
                if(!vis[v]){
                    q[rear++]=v;
                    if(rear>L)rear=0;
                    vis[v]=1;
                    cnt[v]++;
                    if(cnt[v]>L)return false;
                }
            }
        }
    }
    return true;
}
int main()
{
    scanf("%d%d",&L,&P);
    for(int i=1;i<=L;i++)
    scanf("%d",&p[i]);
    int a,b,c;
    memset(first,-1,sizeof(first));
    e=0;
    for(int i=0;i<P;i++){
        scanf("%d%d%d",&a,&b,&c);
        add(a,b,c);
    }
    double l=0,r=1000;
    double ans,mid;
    while(l<=r){
        ans=mid;
        mid=(l+r)/2;
        if(fabs(ans-mid)<1e-6)
        break;
        if(spfa(mid)){
            r=mid;
        }
        else
        l=mid;
    }
    printf("%.2lfn",ans);
    return 0;
}

POJ-3037-Skiing

题意:一个矩形,求左上角到右下角花费的最小时间。。矩形上的点的值代表高度,

已知初始速度v,从a 点到 b 点时,速度变为v(a)*2^(A-B)(A,B为对应点的高度),从 a 到 b 所需的时间为 a 的速度的倒数

,故速度就用倒数表示,,,
最短路最短路View Code

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#define MAXN 105
using namespace std;
int g[MAXN][MAXN];
bool vis[MAXN][MAXN];
int V,R,C;
int x[4]={-1,1,0,0};
int y[4]={0,0,1,-1};
struct point{
    int x,y;
    double v,t;
    bool operator < (const point & a)const{
        return t>a.t;
    }
};
priority_queue<point> q;

double vvv(int x){
    double t=1.0;
    if(x>=0){
        while(x--){
            t=t*2;
        }
    }
    else{
        while(x++){
            t=t/2;
        }
    }
    return t;
}
double BFS(){
    memset(vis,false,sizeof(vis));
    point a;
    a.x=0;a.y=0;a.v=1.0/V;//速度用倒数表示好计算时间
    a.t=0;
    while(!q.empty()){
        q.pop();
    }
    q.push(a);
    while(!q.empty()){
        point newp;
        newp=q.top();
        q.pop();
        if(vis[newp.x][newp.y])continue;
        vis[newp.x][newp.y]=true;
        if(newp.x==R-1&&newp.y==C-1)
        return newp.t;
        for(int i=0;i<4;i++){
            int xx=newp.x+x[i];
            int yy=newp.y+y[i];
            if(xx>=0&&xx<R&&yy>=0&&yy<C){
                if(!vis[xx][yy]){
                    a.x=xx,a.y=yy;
                    a.t=newp.v+newp.t;
                    a.v=newp.v*vvv(g[a.x][a.y]-g[newp.x][newp.y]);
                    q.push(a);
                }
            }
        }
    }
    return -1;
}
int main()
{
    freopen("in.txt","r",stdin);
    while(~scanf("%d%d%d",&V,&R,&C)){
    for(int i=0;i<R;i++)
    for(int j=0;j<C;j++){
        scanf("%d",&g[i][j]);
    }
    printf("%.2lfn",BFS());
    }
    return 0;
}

POJ-3159-Candies

题意:求1与N的相差的最大值

分析:查分约束,a+c>=b则a--->b的路径的权值为c,这么建图就可以像求最短路径那样写。。。最后d[N]即是结果;

这题要用spfa+栈来写,用spfa+队列会超时。。。也可以用dij+优先队列
最短路最短路View Code

#include <iostream>
#include <cstdio>
#include <cstring>
#define MAXM 150050
#define MAXN 30050
#define INF 1000000000
using namespace std;
struct eee{
    int w,v,next;
}edge[MAXM];
int first[MAXN],d[MAXN],q[MAXN],vis[MAXN];
int e;
int N,M;
void add(int u,int v,int w){
    edge[e].v=v;
    edge[e].w=w;
    edge[e].next=first[u];
    first[u]=e++;
}
void init(){
    memset(first,-1,sizeof(first));
    e=0;
}
int spfa(){
    int top=1;
    memset(vis,0,sizeof(vis));
    for(int i=0;i<=N;i++)d[i]=INF;
    d[1]=0;
    q[top]=1;
    while(top){
        int u=q[top--];
        vis[u]=0;
        for(int i=first[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(d[v]>d[u]+edge[i].w){
                d[v]=d[u]+edge[i].w;
                if(!vis[v]){
                    q[++top]=v;
                    vis[v]=1;
                }
            }
        }
    }
    return d[N];
}
int main()
{
    while(scanf("%d%d",&N,&M)==2){
        int a,b,c;
        init();
        for(int i=0;i<M;i++){
            scanf("%d%d%d",&a,&b,&c);
            add(a,b,c);
        }
        printf("%dn",spfa());
    }
    return 0;
}

POJ-3615-Cow Hurdles

题意:用floyd求两点之间的最大值中的最小值
最短路最短路View Code

#include <iostream>
#include <cstdio>
#include <cstring>
#define MAXN 350
#define INF 1000000000
using namespace std;
int g[MAXN][MAXN];
int N,M,T;
void floyd(){

    for(int k=1;k<=N;k++)
    for(int i=1;i<=N;i++)
    for(int j=1;j<=N;j++){
        if(g[i][j]>max(g[i][k],g[k][j])){
            g[i][j]=max(g[i][k],g[k][j]);
        }
    }
}
int main()
{
    scanf("%d%d%d",&N,&M,&T);
    int a,b,c;
    for(int i=0;i<=N;i++)
    for(int j=0;j<=N;j++)
    g[i][j]=INF;
    for(int i=0;i<M;i++){
        scanf("%d%d%d",&a,&b,&c);
        g[a][b]=c;
    }
    floyd();
    for(int i=0;i<T;i++){
        scanf("%d%d",&a,&b);
        if(g[a][b]==INF)printf("-1n");
        else printf("%dn",g[a][b]);
    }
    return 0;
}

POJ-3660-Cow Contest

题解引用Rainy Days

题意:牛之间有绝对的强弱,给出一些胜负关系,问有多少头牛可以确定其绝对排名。

分析:有人说叫闭包传递。这题就是用一种类似于floyd的算法,开始时,如果a胜b则由a到b连一条边。这样所有a能走到的点都是排名在a以后的。所有能走到a的点都是排名在a以前的。用floyd,求出每个点能到达的点。如果有一个点,排名在它之前的和排名在它之后的点之和为n-1,那么它的排名就是确定的。
最短路最短路View Code

#include <iostream>
#include <cstdio>
#include <cstring>
#define MAXN 105
using namespace std;
int g[MAXN][MAXN];
int N,M;
int floyd(){
    for(int k=1;k<=N;k++)
    for(int i=1;i<=N;i++)
    for(int j=1;j<=N;j++){
        if(g[i][k]&&g[k][j])
        g[i][j]=1;
    }
    int ans=0;
    for(int i=1;i<=N;i++){
        int cnt=0;
        for(int j=1;j<=N;j++){
            cnt+=g[i][j]+g[j][i];
        }
        if(cnt==N-1)ans++;
    }
    return ans;
}
int main()
{
    scanf("%d%d",&N,&M);
    memset(g,0,sizeof(g));
    int a,b;
    for(int i=0;i<M;i++){
        scanf("%d%d",&a,&b);
        g[a][b]=1;
    }
    printf("%dn",floyd());
    return 0;
}
  • 占位未完待续
    原文链接: https://www.cnblogs.com/arbitrary/archive/2012/08/18/2645606.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/60073

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月9日 上午9:20
下一篇 2023年2月9日 上午9:20

相关推荐