图论

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\n",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\n");

        else

        printf("%lld\n",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\n",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\n",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\n",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\n");

            else

                printf("%d\n",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\n",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\n");

        else

            printf("%.2f\n",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\n");

        else

        printf("%d\n",ans);

    }

    return 0;

}
View Code

 

你可能感兴趣的:(图论)