图论

POJ 2449 Remmarguts' Date

K短路。

A*+迪杰斯特拉,虽然像是spfa 但是用的迪杰斯特拉的思想,每次找到最小,然后更新。

#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
#include <stdlib.h>
#include <vector>
#include <cmath>
#include <queue>
#include <set>
#include <stack>
#include <queue>
#include <cstring>
using namespace std;
#define INF 0x3ffffff
struct node
{
    int u,v,w,next;
}edge[100001];
int qu[100001],qv[100001],qw[100001];
struct fnode
{
    int g,h,u;
    bool operator < (fnode a)const
    {
        return a.g + a.h < h + g;
    }
};
int first[1001];
int dis[1001];
int cnt[1001];
int in[1001];
int t,str,end,n,k;
/*
f[n] = h[n] + g[n];
h代表n到end的最短距离
g是在状态空间中从初始节点到n节点的实际代价
*/
void CL()
{
    t = 1;
    memset(first,-1,sizeof(first));
}
void add(int u,int v,int w)
{
    edge[t].u = t;
    edge[t].v = v;
    edge[t].w = w;
    edge[t].next = first[u];
    first[u] = t ++;
}
void spfa()
{
    int u,v,i;
    for(i = 1;i <= n;i ++)
    {
        dis[i] = INF;
        in[i] = 0;
    }
    queue<int>que;
    dis[str] = 0;
    in[str] = 1;
    que.push(str);
    while(!que.empty())
    {
        u = que.front();
        in[u] = 0;
        que.pop();
        for(i = first[u];i != -1;i = edge[i].next)
        {
            v = edge[i].v;
            if(dis[v] > dis[u] + edge[i].w)
            {
                dis[v] = dis[u] + edge[i].w;
                if(!in[v])
                {
                    in[v] = 1;
                    que.push(v);
                }
            }
        }
    }
}
int Astar()
{
    fnode cur,nxt;
    int i;
    memset(cnt,0,sizeof(cnt));
    priority_queue <fnode> que;
    cur.u = str;
    cur.g = 0;
    cur.h = dis[cur.u];
    que.push(cur);
    while(!que.empty())
    {
        cur = que.top();
        que.pop();
        cnt[cur.u] ++;
        if(cnt[cur.u] > k) continue;
        if(cnt[end] == k)
        {
            return cur.g;
        }
        for(i = first[cur.u];i != -1;i = edge[i].next)
        {
            nxt.u = edge[i].v;
            nxt.g = cur.g + edge[i].w;
            nxt.h = dis[edge[i].v];
            que.push(nxt);
        }
    }
    return -1;
}
int main()
{
    int i,m,S,T;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        CL();
        for(i = 0;i < m;i ++)
        {
            scanf("%d%d%d",&qu[i],&qv[i],&qw[i]);
            add(qv[i],qu[i],qw[i]);
        }
        scanf("%d%d%d",&S,&T,&k);
        if(S == T)k ++;//
        str = T;
        end = S;
        spfa();
        CL();
        for(i = 0;i < m;i ++)
        {
            add(qu[i],qv[i],qw[i]);
        }
        str = S;
        end = T;
        printf("%d
",Astar());
    }
    return 0;
}
View Code

POJ 3013 Big Christmas Tree

有意思的一题,把求和式子转换一下,就是最短路了。

#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
#include <stdlib.h>
#include <vector>
#include <cmath>
#include <queue>
#include <set>
#include <stack>
#include <queue>
#include <cstring>
using namespace std;
#define INF 20000000000LL
#define LL long long
struct node
{
    int u,v,w,next;
}edge[210000];
int first[50100];
LL dis[50100];
int in[50100];
int wgt[50100];
int t,n;
void CL()
{
    t = 1;
    memset(first,-1,sizeof(first));
}
void add(int u,int v,int w)
{
    edge[t].u = u;
    edge[t].v = v;
    edge[t].w = w;
    edge[t].next = first[u];
    first[u] = t ++;
}
LL spfa()
{
    int i,u,v;
    for(i = 1;i <= n;i ++)
    {
        dis[i] = INF;
        in[i] = 0;
    }
    queue<int> que;
    in[1] = 1;
    dis[1] = 0;
    que.push(1);
    while(!que.empty())
    {
        u = que.front();
        in[u] = 0;
        que.pop();
        for(i = first[u];i != -1;i = edge[i].next)
        {
            v = edge[i].v;
            if(dis[v] > dis[u] + edge[i].w)
            {
                dis[v] = dis[u] + edge[i].w;
                if(!in[v])
                {
                    in[v] = 1;
                    que.push(v);
                }
            }
        }
    }
    LL ans = 0;
    for(i = 1;i <= n;i ++)
    {
        if(dis[i] == INF)
        return -1;
        ans += dis[i]*wgt[i];
    }
    return ans;
}
int main()
{
    int cas,i,m;
    scanf("%d",&cas);
    while(cas--)
    {
        CL();
        scanf("%d%d",&n,&m);
        for(i = 1;i <= n;i ++)
        scanf("%d",&wgt[i]);
        for(i = 0;i < m;i ++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);
            add(v,u,w);
        }
        LL ans = spfa();
        if(ans == -1)
        printf("No Answer
");
        else
        printf("%lld
",ans);
    }
    return 0;
}
View Code

POJ 3463 Sightseeing

最短路条数+次短路条数,spfa形式的迪杰斯特拉,不是很懂此题的思路。

#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
#include <stdlib.h>
#include <vector>
#include <cmath>
#include <queue>
#include <set>
#include <stack>
#include <queue>
#include <cstring>
using namespace std;
#define INF 0x3ffffff
struct node
{
    int u,v,w,next;
}edge[100000];
int first[10000];
int dis[10000][2];
int cnt[10000][2];
int in[10000][2];
int n,t,S,T;
struct fnode
{
    int u,w,k;
    bool operator < (fnode a)const
    {
        return a.w < w;
    }
};
void CL()
{
    t = 1;
    memset(first,-1,sizeof(first));
}
void add(int u,int v,int w)
{
    edge[t].u = u;
    edge[t].v = v;
    edge[t].w = w;
    edge[t].next = first[u];
    first[u] = t ++;
}
int spfa()
{
   int i,j,u,v;
   fnode cur,nxt;
   for(i = 1;i <= n;i ++)
   {
       for(j = 0;j < 2;j ++)
       {
           dis[i][j] = INF;
           cnt[i][j] = 0;
           in[i][j] = 0;
       }
   }
   dis[S][0] = 0;
   cnt[S][0] = 1;
   cnt[S][1] = 1;
   priority_queue<fnode>que;
   cur.u = S;
   cur.w = 0;
   cur.k = 0;
   que.push(cur);
   while(!que.empty())
   {
       cur = que.top();
       que.pop();
       u = cur.u;
       if(in[u][cur.k])
       continue;
       in[u][cur.k] = 1;
       for(i = first[u];i != -1;i = edge[i].next)
       {
           v = edge[i].v;
           if(dis[v][0] > cur.w + edge[i].w)
           {
               dis[v][1] = dis[v][0];
               cnt[v][1] = cnt[v][0];
               dis[v][0] = cur.w + edge[i].w;
               cnt[v][0] = cnt[u][cur.k];
               nxt.u = v;
               nxt.w = dis[v][0];
               nxt.k = 0;
               que.push(nxt);
               nxt.u = v;
               nxt.w = dis[v][1];
               nxt.k = 1;
               que.push(nxt);
           }
           else if(dis[v][0] == cur.w + edge[i].w)
           {
               cnt[v][0] += cnt[u][cur.k];
           }
           else if(dis[v][1] > cur.w + edge[i].w)
           {
               dis[v][1] = cur.w + edge[i].w;
               cnt[v][1] = cnt[u][cur.k];
               nxt.u = v;
               nxt.w = dis[v][1];
               nxt.k = 1;
               que.push(nxt);
           }
           else if(dis[v][1] == cur.w + edge[i].w)
           {
               cnt[v][1] += cnt[u][cur.k];
           }
       }
   }
   if(dis[T][0] == dis[T][1]-1)
   return cnt[T][0] + cnt[T][1];
   else
   return cnt[T][0];
}
int main()
{
    int cas,m,i,u,v,w;
    scanf("%d",&cas);
    while(cas--)
    {
        CL();
        scanf("%d%d",&n,&m);
        for(i = 0;i < m;i ++)
        {
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);
        }
        scanf("%d%d",&S,&T);
        printf("%d
",spfa());
    }
    return 0;
}
View Code

 POJ 3613 Cow Relays

s 到 e的经过了n条边的最短路。

#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
#include <stdlib.h>
#include <vector>
#include <cmath>
#include <queue>
#include <set>
#include <stack>
#include <queue>
#include <cstring>
using namespace std;
#define INF 1000000000
int p[301][301];
int ans[301][301];
int dis[301][301];
int tmp[301][301];
int qu[501];
int qv[501];
int qw[501];
int que[501];
int flag[1001];
int num,s,e;
#define MAXN 301
void floyd(int c[][MAXN], int a[][MAXN], int b[][MAXN])
{
    for(int k = 1; k < num; k++)
        for(int i = 1; i < num; i++)
            for(int j = 1; j < num; j++)
                if(c[i][j] > a[i][k] + b[k][j])
                    c[i][j] = a[i][k] + b[k][j];
}
void copy(int a[][MAXN], int b[][MAXN])
{
    for(int i = 1; i < num; i++)
        for(int j = 1; j < num; j++)
        {
            a[i][j] = b[i][j];
            b[i][j] = INF;
        }
}
int qmod(int k)
{
    while(k)
    {
        if(k & 1)
        {
            floyd(dis, ans, p);
            copy(ans, dis);
        }
        floyd(tmp, p, p);
        copy(p, tmp);
        k >>= 1;
    }
    return ans[flag[s]][flag[e]];
}
int main()
{
    int i,j,n,m,u,v,w;
    scanf("%d%d%d%d",&n,&m,&s,&e);
    for(i = 1; i <= 300; i ++)
    {
        for(j = 1; j <= 300; j ++)
        {
            p[i][j] = INF;
            ans[i][j] = INF;
            dis[i][j] = INF;
            tmp[i][j] = INF;
        }
        ans[i][i] = 0;//注意这里
    }
    num = 1;
    for(i = 0; i < m; i ++)
    {
        scanf("%d%d%d",&qw[i],&qu[i],&qv[i]);
        if(flag[qu[i]] == 0)
            flag[qu[i]] = num++;
        if(flag[qv[i]] == 0)
            flag[qv[i]] = num++;
        u = flag[qu[i]];
        v = flag[qv[i]];
        w = qw[i];
        p[u][v] = min(p[u][v],w);
        p[v][u] = min(p[v][u],w);
    }
    printf("%d
",qmod(n));
}
View Code

 POJ 3621 Sightseeing Cows

最优比率生成环

#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
#include <stdlib.h>
#include <vector>
#include <cmath>
#include <queue>
#include <set>
#include <stack>
#include <queue>
#include <cstring>
using namespace std;
#define INF 0x3f3f3f3f
#define eps 1e-3
struct node
{
    int u,v,next;
    double w;
}edge[10000];
int p[1001];
int first[1001];
double dis[1001];
int in[1001];
int num[1001];
int t,n;
void CL()
{
    t = 1;
    memset(first,-1,sizeof(first));
}
void add(int u,int v,int w)
{
    edge[t].u = u;
    edge[t].v = v;
    edge[t].w = w;
    edge[t].next = first[u];
    first[u] = t ++;
}
int spfa(double r)
{
    int i,u,v;
    double w;
    for(i = 1;i <= n;i ++)
    {
        dis[i] = INF;
        num[i] = 0;
        in[i] = 0;
    }
    dis[1] = 0;
    in[1] = 1;
    queue<int>que;
    que.push(1);
    while(!que.empty())
    {
        u = que.front();
        que.pop();
        in[u] = 0;
        for(i = first[u];i != -1;i = edge[i].next)
        {
            v = edge[i].v;
            w = -p[v] + r*edge[i].w;
            if(dis[v] > dis[u] + w)
            {
                dis[v] = dis[u] + w;
                if(!in[v])
                {
                    in[v] = 1;
                    num[v] ++;
                    if(num[v] > n)
                    return 1;
                    que.push(v);
                }
            }
        }
    }
    return 0;
}
int main()
{
    int m,i,u,v;
    double w;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        CL();
        for(i = 1;i <= n;i ++)
        scanf("%d",&p[i]);
        for(i = 1;i <= m;i ++)
        {
            scanf("%d%d%lf",&u,&v,&w);
            add(u,v,w);
        }
        double str,end,mid;
        str = 0;
        end = 10000000;
        while(str+eps < end)
        {
            mid = (str + end)/2;
            if(spfa(mid))
            str = mid;
            else
            end = mid;
        }
        printf("%.2lf
",str);
    }

    return 0;
}
View Code

 POJ 3635 Full Tank?

二维的spfa,这题主要是会超时,首先转移有两种,加1单位的油或者 走向下个城市,这样会spfa的比较快,然后写成spfa形式的迪杰斯特拉,就可AC。

#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
#include <stdlib.h>
#include <vector>
#include <cmath>
#include <queue>
#include <set>
#include <stack>
#include <queue>
#include <cstring>
using namespace std;
#define INF 0x3f3f3f3f
#define eps 1e-3
struct node
{
    int u,v,w,next;
} edge[30000];
struct city
{
    int u,c,w;
    bool operator < (city a)const
    {
        return a.w < w;
    }
};
int t,n;
int first[1001];
int p[1001];
int dis[1001][101];
int in[1001][101];
int s,e,c;
void CL()
{
    t = 1;
    memset(first,-1,sizeof(first));
}
void add(int u,int v,int w)
{
    edge[t].u = u;
    edge[t].v = v;
    edge[t].w = w;
    edge[t].next = first[u];
    first[u] = t ++;
}
int spfa()
{
    int i,j,u,v,tc;
    city cur,nxt;
    for(i = 0; i < n; i ++)
    {
        for(j = 0; j <= c; j ++)
        {
            dis[i][j] = INF;
            in[i][j] = 0;
        }
    }
    priority_queue<city>que;
    cur.u = s;
    cur.c = 0;
    cur.w = 0;
    dis[cur.u][cur.c] = 0;
    in[s][0] = 1;
    que.push(cur);
    while(!que.empty())
    {
        cur = que.top();
        u = cur.u;
        tc = cur.c;
        que.pop();
        if(u == e)
        return cur.w;
        in[u][tc] = 0;
        if(tc + 1 <= c)//加油
        {
            if(dis[u][tc+1] > dis[u][tc] + p[u])
            {
                dis[u][tc+1] = dis[u][tc] + p[u];
                v = u;
                j = tc+1;
                nxt.u = v;
                nxt.c = j;
                nxt.w = dis[v][j];
                que.push(nxt);
            }
        }
        for(i = first[u]; i != -1; i = edge[i].next)
        {
            v = edge[i].v;
            if(tc >= edge[i].w)//走点
            {
                j = tc-edge[i].w;
                if(dis[v][j] > dis[u][tc])
                {
                    dis[v][j] = dis[u][tc];
                    nxt.u = v;
                    nxt.c = j;
                    nxt.w = dis[v][j];
                    que.push(nxt);
                }
            }
        }
    }
    return -1;
}
int main()
{
    int m,i,q;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        CL();
        for(i = 0; i < n; i ++)
            scanf("%d",&p[i]);
        for(i = 0; i < m; i ++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);
            add(v,u,w);
        }
        scanf("%d",&q);
        while(q--)
        {
            scanf("%d%d%d",&c,&s,&e);
            int temp = spfa();
            if(temp == -1)
                printf("impossible
");
            else
                printf("%d
",temp);
        }
    }
    return 0;
}
View Code

 POJ 2728 Desert King

最优比率生成树

#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
#include <stdlib.h>
#include <vector>
#include <cmath>
#include <queue>
#include <string>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cstring>
using namespace std;
#define INF 100000000
#define eps 1e-4
struct node
{
    double x,y,z;
    double w;
}p[1001];
double low[1001];
int o[1001],n;
double fun(int u,int v,double mid)
{
    double l,c;
    l = sqrt((p[u].x-p[v].x)*(p[u].x-p[v].x) + (p[u].y-p[v].y)*(p[u].y-p[v].y));
    c = fabs(p[u].z-p[v].z);
    return c-mid*l;
}
double judge(double mid)
{
    int i,j,k;
    double ans = 0,minz;
    for(i = 1;i <= n;i ++)
    {
        low[i] = INF;
        o[i] = 0;
    }
    low[1] = 0;
    for(i = 1;i <= n;i ++)
    {
        minz = INF;
        for(j = 1;j <= n;j ++)
        {
            if(!o[j]&&minz > low[j])
            {
                minz = low[j];
                k = j;
            }
        }
        o[k] = 1;
        ans += minz;
        for(j = 1;j <= n;j ++)
        {
            double temp = fun(k,j,mid);
            if(!o[j]&&low[j] > temp)
            {
                low[j] = temp;
            }
        }
    }
    return ans;
}
int main()
{
    int i;
    double str,end,mid;
    while(scanf("%d",&n)!=EOF)
    {
        if(n == 0) break;
        for(i = 1;i <= n;i ++)
        {
            scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].z);
        }
        str = 0;
        end = 100000;
        while(str + eps < end)
        {
            mid = (str + end)/2;
            if(judge(mid) <= 0)
            end = mid;
            else
            str = mid;
        }
        printf("%.3lf
",str);
    }
    return 0;
}
View Code

POJ 3164 Command Network

最小树形图,抄的模板,把序号 改成从1开始不知道为什么过不了。

#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
#include <stdlib.h>
#include <vector>
#include <cmath>
#include <queue>
#include <string>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cstring>
using namespace std;
#define INF ~0u>>1
#define N 1001
#define eps 1e-8
int t;
struct node
{
    int u,v;
    double w;
} edge[100000];
struct point
{
    double x,y;
} p[N];
double in[N];
int pre[N];
int vis[N];
int id[N];
int n,m;

double dis(point a,point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double Directed_MST(int root)
{
    double ret = 0;
    int i, u, v;
    while(true)
    {
        for(i = 0; i < n; i ++)
        in[i] = INF;
        for(i = 1;i <= m;i ++)
        {
            u = edge[i].u;
            v = edge[i].v;
            if(edge[i].w < in[v] && u != v)
            {
                in[v] = edge[i].w;
                pre[v] = u;
            }
        }
        for(i = 0;i < n;i ++)     //如果存在除root以外的孤立点,则不存在最小树形图
        {
            if(i == root)   continue;
            if(in[i] == INF)    return -1;
        }
        int cnt = 0;
        memset(id,-1,sizeof(id));
        memset(vis,-1,sizeof(vis));
        in[root] = 0;
        for(i = 0;i < n;i ++)    //找环
        {
            ret += in[i];
            int v = i;
            while(vis[v] != i && id[v] == -1 && v != root)
            {
                vis[v] = i;
                v = pre[v];
            }
            if(v != root && id[v] == -1)    //重新标号
            {
                for(u = pre[v]; u != v; u = pre[u])
                {
                    id[u] = cnt;
                }
                id[v] = cnt++;
            }
        }
        if(cnt == 0)    break;
        for(i = 0;i < n;i ++)
        {
            if(id[i] == -1) id[i] = cnt++;    //重新标号
        }
        for(i = 1;i <= m;i ++)     //更新其他点到环的距离
        {
            v = edge[i].v;
            edge[i].u = id[edge[i].u];
            edge[i].v = id[edge[i].v];
            if(edge[i].u != edge[i].v)
            {
                edge[i].w -= in[v];
            }
        }
        n = cnt;
        root = id[root];
    }
    return ret;
}
int main()
{
    int i,u,v;
    double ans;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(i = 0; i < n; i ++)
        {
            scanf("%lf%lf",&p[i].x,&p[i].y);
        }
        for(i = 1; i <= m; i ++)
        {
            scanf("%d%d",&u,&v);
            u --;
            v --;
            edge[i].u = u;
            edge[i].v = v;
            edge[i].w = dis(p[u],p[v]);
        }
        ans = Directed_MST(0);
        if(ans == -1)
            printf("poor snoopy
");
        else
            printf("%.2f
",ans);
    }
    return 0;
}
View Code

POJ 3522 Slim Span

暴力...

#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
#include <stdlib.h>
#include <vector>
#include <cmath>
#include <queue>
#include <string>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cstring>
using namespace std;
#define INF 0x7ffffff
struct node
{
    int u,v,w;
}edge[10001];
int o[101];
int num;
bool cmp(node a,node b)
{
    return a.w < b.w;
}
int find(int x)
{
    while(x != o[x])
    x = o[x];
    return x;
}

void merge(int x,int y)
{
    x = find(x);
    y = find(y);
    if(o[x] != y)
    {
        num ++;
        o[x] = y;
    }
}

int main()
{
    int u,v,i,j,w,ans,n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n == 0&&m == 0) break;
        for(i = 0;i < m;i ++)
        scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
        sort(edge,edge+m,cmp);
        ans = INF;
        for(i = 0;i < m;i ++)
        {
            for(j = 1;j <= n;j ++)
            o[j] = j;
            num = 0;
            for(j = i;j < m;j ++)
            {
                u = edge[j].u;
                v = edge[j].v;
                w = edge[j].w;
                if(w - edge[i].w > ans)
                break;
                merge(u,v);
                if(num == n-1)
                {
                    ans = min(ans,w-edge[i].w);
                    break;
                }
            }
        }
        if(ans == INF)
        printf("-1
");
        else
        printf("%d
",ans);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/naix-x/p/3878550.html