《挑战程序设计竞赛》2.5 它们其实都是图

来源:互联网 发布:秦柯 python 编辑:程序博客网 时间:2024/05/18 03:46

POJ - 2139  Six Degrees of Cowvin Bacon(裸floyd)

题意:N头牛,拍了M部电影,同一部电影中的搭档们距离1,求最小度数之和。


#include <cstdio>#include <queue>#include <cstring>#include <algorithm>#include <iostream>using namespace std;const int mod = 1e9;const int maxn_e = 10005;const int maxn_v = 300 + 5;const int INF = 0x3f3f3f3f;//用LL的时候要修改int d[maxn_v][maxn_v];int a[maxn_v];void init(int V){    for(int i = 1; i <= V; i++)    {        for(int j = 1;j <= V; j++)        {            d[i][j] = (i == j) ?  0 : INF;        }    }}void Floyd(int V){    for(int k = 1;k <= V; k++)    {        for(int i = 1; i <= V; i++)        {            for(int j = 1; j <= V; j++)            {                d[i][j] = min(d[i][j], d[i][k] + d[k][j]);//看情况加不加 判断 INF  d[i][k] d[k][j]            }        }    }}int main(){    int V, M;    scanf("%d%d", &V, &M);    init(V);    //输入数据并建图    for(int i = 0; i < M; i++)    {        int n, t;        scanf("%d", &n);        for(int j = 0; j < n; j++)        {            scanf("%d", &a[j]);        }        for(int j = 0; j < n; j++)        {            for(int k = 0; k < j; k++)            {                d[ a[j] ][ a[k] ] = d[ a[k] ][ a[j] ] = 1;            }        }    }    Floyd(V);    int minn = INF;    for(int i = 1; i <= V; i++)    {        int tot = 0;        for(int j = 1; j <= V; j++)        {            if(i == j) continue;            tot += d[i][j];        }        minn = min(minn, 100 * tot / (V - 1));    }    cout << minn << endl;    return 0;}

POJ - 3259  Wormholes(判负环)

题意:

  虫洞问题,现在有n个点,m条边,代表现在可以走的通路,比如从a到b和从b到a需要花费c时间,现在在地上出现了w个虫洞,虫洞的意义就是你从a到b话费的时间是-c(时间倒流,并且虫洞是单向的),现在问你能不能从某个点开始走,回到从前。即找负环。

思路:

  言下之意就是判断有无负环,bellman或者spfa一套模板就行了。

#include <cstdio>#include <vector>#include <queue>#include <cstring>using namespace std;int n, m, w;const int maxv = 500+5;const int INF = 0x3f3f3f3f;int vis[maxv],cnt[maxv],dis[maxv];struct edge{    int to, co;    edge(int tt, int cc):to(tt), co(cc){}};vector<edge>G[maxv];void ma_init(){    scanf("%d%d%d", &n, &m, &w);    for(int i = 1; i <= n; i++)//vector要记得重置        G[i].clear();    int s, e, t;    for(int i = 0; i < m; i++)    {        scanf("%d%d%d", &s, &e, &t);        G[s].push_back({e, t});//因为这个边是双向的,所以两边都要压进去。        G[e].push_back({s, t});    }    for(int i = 0; i < w; i++)    {        scanf("%d%d%d", &s, &e, &t);        G[s].push_back({e, -t});//虫洞是单向的 且是负值    }}bool spfa(int s){    memset(vis, 0, sizeof(vis));    memset(cnt, 0, sizeof(cnt));    for(int i = 1; i <= n; i++) dis[i] = INF;//初始化distant数组    //进队之前的初始化    queue<int>que;    dis[s] = 0;    que.push(s);    vis[s] = cnt[s] = 1;//vis数组表示 s结点在队列中 cnt数组表示 s结点入队一次    while(!que.empty())    {        int v = que.front();que.pop();//取出队列中队首的顶点的编号v        vis[v] = 0;//弹出之后消除标记        for(int i = 0; i < G[v].size(); i++)//对顶点v的所有相连的边进行一次遍历。        {            edge e = G[v][i];            if(dis[e.to] > dis[v] + e.co)//进行更新            {                dis[e.to] = dis[v] + e.co;                if(vis[e.to] == 0)//若顶点e.to此时不在队列中,则压进队中,并更新一系列数据                {                    que.push(e.to);                    vis[e.to] = 1;                    cnt[e.to]++;                    if(cnt[e.to] > n) return false;//如果有一个顶点进队了n次,则存在负环                }            }        }    }    return true;}int main(){    int T;    scanf("%d",&T);    while(T--)    {        ma_init();        if(!spfa(1) || dis[1]<0 )            printf("YES\n");        else            printf("NO\n");    }    return 0;}


POJ - 3268  Silver Cow Party(spfa or dijkstra)

题意:

  给出n个点和m条边,接着是m条边,代表从牛a到牛b需要花费c时间,现在所有牛要到牛x那里去参加聚会,并且所有牛参加聚会后还要回来,给你牛x,除了牛x之外的牛,他们都有一个参加聚会并且回来的最短时间,从这些最短时间里找出一个最大值输出。

思路:

  回家的时候不用说,一个裸的最短路问题。去聚会的问题稍微转换一下,是不是等价于把所有的边反向以后,从牛x家求一个最短路。

#include <cstdio>#include <vector>#include <queue>#include <algorithm>using namespace std;const int maxv = 1000+5;const int INF = 0x3f3f3f3f;typedef pair<int, int>pii;int dis[maxv], vis[maxv], tot[maxv];struct edge{    int to, co;    edge(int tt, int cc):to(tt), co(cc){}};vector<edge>G1[maxv];vector<edge>G2[maxv];void init(int V){    for(int i = 1; i <= V; i++)    {        G1[i].clear();        G2[i].clear();    }}void dijkstra(int s, int V, vector<edge>G[]){    for(int i = 0; i <= V; i++) dis[i] = INF;    //通过指定greater<P>参数,堆按照first从小到大的顺序取出值。    priority_queue<pii, vector<pii>, greater<pii> >que;    dis[s] = 0;    que.push({0, s});    while(!que.empty())    {        pii p = que.top();que.pop();        int v = p.second, d = p.first;        if(d > dis[v]) continue;//剪枝:比最短路还大,没有更新的意义        for(int i = 0; i < G[v].size(); i++)        {            edge &e = G[v][i];//因为会有修改,所以取引用。            if(dis[e.to] > dis[v] + e.co)            {                dis[e.to] = dis[v] + e.co;                que.push({dis[e.to], e.to});            }        }    }    for(int i = 1; i <= V; i++)        tot[i] += dis[i];}int main(){    int n, m, x;    scanf("%d%d%d", &n, &m, &x);//一共有n只牛,m条路,在x牛处举行party    init(n);    for(int i = 0; i < m; i++)    {        int u, v, w;        scanf("%d%d%d", &u, &v, &w);        G1[u].push_back({v, w});        G2[v].push_back({u, w});    }    dijkstra(x, n, G1);    dijkstra(x, n, G2);    int ans = *max_element(tot, tot + 1 + n);    printf("%d\n", ans);    return 0;}

POJ - 1258  Agri-Net(最小生成树裸题)

题意:

  有n个农场,已知这n个农场都互相相通,有一定的距离,现在每个农场需要装光纤,问怎么安装光纤能将所有农场都连通起来,并且要使光纤距离最小,输出安装光纤的总距离。

思路:

  这题特么是多case的我擦。。

#include <cstdio>#include <queue>#include <cstring>#include <algorithm>#include <iostream>using namespace std;const int mod = 1e9;const int maxn = 100 + 5;int ma[maxn][maxn];typedef pair<int, int>pii;struct edge{    int u, v, w;    bool operator < (const edge &other) const    {        return w < other.w;    }}edges[maxn * maxn];int pa[maxn];void init(int n){    for(int i = 0; i <= n; i++)        pa[i] = i;}int uf_find(int x){    return pa[x] == x ? x : (pa[x] = uf_find(pa[x]));}bool same(int x,int y){return (uf_find(x) == uf_find(y)) ? true : false;}void join(int x, int y){    int fx = uf_find(x), fy = uf_find(y);    if(fx != fy) pa[fx] = fy;}int kruskal(int vs, int es){    int ret = 0;    sort(edges, edges + es);    init(vs);    for(int i = 0; i < es; i++)    {        edge e = edges[i];        if(!same(e.v, e.u))        {            ret += e.w;            join(e.v, e.u);        }    }    return ret;}int main(){    int n;    while(~scanf("%d", &n))    {        int cnt = 0;        for(int i = 1; i <= n; i++)        {            for(int j = 1; j <= n; j++)            {                int x;                scanf("%d", &x);                if(i == j)  continue;                edges[cnt].v = i, edges[cnt].u = j, edges[cnt].w = x;                cnt++;            }        }        cout << kruskal(n, cnt) << endl;    }    return 0;}


POJ - 2377  Bad Cowtractors(最大生成树)

题意:

  坏奶牛:为了破坏农夫约翰的光纤计划,奶牛决定骗丫拉一条最长的网络。

思路:

  最小变最大。。

  wa点:要判一下有没有孤点

#include <cstdio>#include <queue>#include <cstring>#include <algorithm>#include <iostream>using namespace std;const int mod = 1e9;const int maxn = 100 + 5;typedef pair<int, int>pii;//最大生成树struct edge{    int u, v, w;    bool operator < (const edge &other) const    {        return w > other.w;    }}edges[20000 + 5];int pa[1000 + 5];void init(int n){    for(int i = 0; i <= n; i++)        pa[i] = i;}int uf_find(int x){    return pa[x] == x ? x : (pa[x] = uf_find(pa[x]));}bool same(int x,int y){return (uf_find(x) == uf_find(y)) ? true : false;}void join(int x, int y){    int fx = uf_find(x), fy = uf_find(y);    if(fx != fy) pa[fx] = fy;}int kruskal(int vs, int es){//最大生成树 还要判断一个悬浮孤点    init(vs);    sort(edges, edges + es);    int ret = 0;    int cnt_num = 1;    for(int i = 0; i < es; i++)    {        edge e = edges[i];        if(!same(e.v, e.u))        {            ret += e.w;            join(e.v, e.u);            cnt_num++;        }    }    if(cnt_num < vs)    return -1;    return ret;}int main(){    int vs, es;    scanf("%d%d", &vs, &es);    for(int i = 0; i < es; i++)    {        scanf("%d%d%d", &edges[i].u, &edges[i].v, &edges[i].w);    }    cout << kruskal(vs, es) << endl;    return 0;}

POJ - 2395  Out of Hay(最小生成树)

题意:

  求干草:奶牛没草吃了,要去附近的农场找,求最短遍历路径上最长的那条路。

思路:

  还要提示咩。

#include <cstdio>#include <queue>#include <cstring>#include <algorithm>#include <iostream>using namespace std;const int mod = 1e9;const int maxn = 100 + 5;const int INF = 0x3f3f3f3f;typedef pair<int, int>pii;struct edge{    int u, v, w;    bool operator < (const edge &other) const    {        return w < other.w;    }}edges[10000 + 5];int pa[2000 + 5];void init(int n){    for(int i = 0; i <= n; i++)        pa[i] = i;}int uf_find(int x){    return pa[x] == x ? x : (pa[x] = uf_find(pa[x]));}bool same(int x,int y){return (uf_find(x) == uf_find(y)) ? true : false;}void join(int x, int y){    int fx = uf_find(x), fy = uf_find(y);    if(fx != fy) pa[fx] = fy;}int kruskal(int vs, int es){    init(vs);    sort(edges, edges + es);    int ret = 0;    int maxedge = -INF;    for(int i = 0; i < es; i++)    {        edge e = edges[i];        if(!same(e.v, e.u))        {            ret += e.w;            join(e.v, e.u);            maxedge = max(maxedge, e.w);        }    }    cout << maxedge << endl;    return ret;}int main(){    int vs, es;    scanf("%d%d", &vs, &es);    for(int i = 0; i < es; i++)    {        scanf("%d%d%d", &edges[i].u, &edges[i].v, &edges[i].w);    }    kruskal(vs, es);    return 0;}









0 0
原创粉丝点击