kuangbin带你飞 最短路 题解

求一个图最短路边的办法。好像下面的那个有问题。单向边和双向边一定是有区别的。这个比较容易。参照该文的最短路网络流题目和连通图题目一题求最短路关节边

另外上述2个题目的代码好像有问题。

在UVALIVE 6885中不能得到AC。不知道原因。感觉是对的。

另一种判断最短路的方法就是

从起点到u+从终点到v+边U,V权值==最短路值那么这条边为最短路

这种方案的代码

for (int i = 1 ; i <= M ; i++) {
            scanf("%d%d%d",&u[i],&v[i],&w[i]);
            u[i]++;v[i]++;
            S.add_edge(u[i],v[i],w[i],i);
            S.add_edge(v[i],u[i],w[i],i);
            T.add_edge(u[i],v[i],w[i],i);
            T.add_edge(v[i],u[i],w[i],i);
        }
        S.dijkstra(source);
        T.dijkstra(target);
        long long ans = 0;
        for (int i = 1 ; i <= P ; i++) {
            for (int j = S.head[i] ; j != -1 ; j = S.edge[j].next) {
                int v = S.edge[j].v;
                if (S.dis[i] + T.dis[v] + S.edge[j].w == S.dis[target])
                    //这条边为最短路边
            }
        }

同时另一种可能存在问题的方法如下

 for (int i = 1 ; i <= m ; i++)
        {
            scanf("%d%d%I64d",&u[i],&v[i],&w[i]);
            S.add_edge(u[i],v[i],w[i],i);
            S.add_edge(v[i],u[i],w[i],i);
            T.add_edge(u[i],v[i],w[i],i);
            T.add_edge(v[i],u[i],w[i],i);
        }
        S.dijkstra(s);
        T.dijkstra(t);
        init();
        for (int i = 1 ; i <= m ; i++)
        {
            int tu = u[i];
            int tv = v[i];
            LL tw = w[i];
            if ((S.dis[tu] + tw == S.dis[tv] && T.dis[tv] + tw == T.dis[tu])
                ||(S.dis[tv] + tw == S.dis[tu] && T.dis[tu] + tw == T.dis[tv]))
            {
                add_edge(tu,tv,tw,i);
                add_edge(tv,tu,tw,i);//这里是为了处理tarjan无向图 其实就是u[i],v[i],w[i]这条边为最短路边。
            }
        }
        slove(n);

对于上述方案的有向图 建图有区别

如下

 

for (int i = 0 ; i < M ; i++)
        {
            scanf("%d%d%d",&u[i],&v[i],&w[i]);
            St.add_edge(u[i],v[i],w[i],i + 1);
            //St.add_edge(v[i],u[i],w[i],i + 1);
            //Ted.add_edge(u[i],v[i],w[i],i + 1);
            Ted.add_edge(v[i],u[i],w[i],i + 1);
        }
        scanf("%d%d",&A,&B);
        St.dijkstra(A);
       /* if (St.dis[B] == INF)
        {
            puts("0");
            continue;
        }
        */
        Ted.dijkstra(B);
        for (int i = 0 ; i < M ; i++)
        {
            int tu = u[i];
            int tv = v[i];
            int tw = w[i];
            if (tu == tv) continue;
            if ((St.dis[tu] + tw == St.dis[tv] && Ted.dis[tv] + tw == Ted.dis[tu])
                ||(St.dis[tv] + tw == St.dis[tu] && Ted.dis[tu] + tw == Ted.dis[tv]))
            {
                add_edge(tu,tv,1);//这里添加的是网络流的边无需双向
            }
        }

 

POJ 2387 Til the Cows Come Home

直接求最短路末班题。我这里是dijkstra+优先队列优化的班

#include 
#include <set>
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include <string>
#include 
#include 
#include 
#include 
#include 
#include 
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {
      return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 4100;
const int MAXM = 40005;
const int INF = 0x3f3f3f3f;
struct Edge
{
    int u,v,next;
    int w;
}edge[MAXM];
int head[MAXN],tot;

void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
}

void add_edge(int u,int v,int w)
{
    edge[tot].u = u;
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].next = head[u];
    head[u] = tot++;
}

struct heapnode
{
    int val,u;
    bool operator < (const heapnode &rhs) const
    {
        return val > rhs.val;
    }
};

bool done[MAXN];
int dis[MAXN];
priority_queueq;
int N,M;

void dijkstra(int s)
{
    memset(done,false,sizeof(done));
    while (!q.empty()) q.pop();
    memset(dis,0x3f,sizeof(dis));
    dis[s] = 0;
    q.push((heapnode){dis[s],s});
    while (!q.empty())
    {
        heapnode x = q.top(); q.pop();
        int u = x.u;
        if (done[u]) continue;
        done[u] = true;
        for (int i = head[u] ; i != -1 ; i = edge[i].next)
        {
            int v = edge[i].v;
            if (dis[v] > dis[u] + edge[i].w)
            {
                dis[v] = dis[u] + edge[i].w;
                q.push((heapnode){dis[v],v});
            }
        }
    }
}

int main()
{
    while (scanf("%d%d",&N,&M) != EOF)
    {
        swap(N,M);
        init();
        for (int i = 0 ; i < M ; i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            add_edge(u,v,w);
            add_edge(v,u,w);
        }
        dijkstra(1);
        printf("%d\n",dis[N]);
    }
    return 0;
}
View Code

POJ 2253 Frogger

从1号点跳到2号点所经过的路径中最短的路径长度

可以用类似最小生成树的思路来解

这里用的kruskal

#include 
#include <set>
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include <string>
#include 
#include 
#include 
#include 
#include 
#include 
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {
      return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 205;
const int MAXM = MAXN * MAXN;
struct Edge
{
    int u,v;
    double w;
    friend bool operator <(const Edge &a,const Edge &b)
    {
        return a.w < b.w;
    }
}edge[MAXM];
int fa[MAXN],tot,N;
double x[MAXN],y[MAXN];
int Find(int x) {
      return x == fa[x] ? x : fa[x] = Find(fa[x]);}

bool judge()
{
    int fu = Find(1);
    int fv = Find(2);
    if(fu == fv) return true;
    return false;
}

void build()
{
    tot = 0;
    for (int i = 1 ; i <= N ; i++)scanf("%lf%lf",&x[i],&y[i]);
    for (int i = 1 ; i <= N ; i++)
    {
        for (int j = i + 1 ; j <= N ; j++)
        {
            double dis = sqrt((x[i] - x[j]) * (x[i] - x[j]) +
                        (y[i] - y[j]) * (y[i] - y[j]));
            edge[tot].u = i;
            edge[tot].v = j;
            edge[tot].w = dis;
            tot++;
        }
    }
}


double kruskal()
{
    int cnt = 0;
    double ret = 0.0;
    sort(edge,edge + tot);
    for (int i = 0 ; i <= N ; i++) fa[i] = i;
    for (int i = 0 ; i < tot ; i++)
    {
        if (judge()) return ret;
        int fu = Find(edge[i].u);
        int fv = Find(edge[i].v);
        if (fu != fv)
        {
            fa[fu] = fv;
            cnt++;
            ret = max(ret,edge[i].w);
        }
    }
    return ret;
}

int main()
{
    //freopen("sample.txt","r",stdin);
    int kase = 1;
    while (scanf("%d",&N) != EOF)
    {
        if (N == 0) break;
        printf("Scenario #%d\nFrog Distance = ",kase++);
        build();
        printf("%.3f\n",kruskal());
        putchar('\n');
    }
    return 0;
}
View Code

另一种建立在理解dijkstra的基础上的代码。根据题意来确定相关更新

实际上这套题最困扰我的就是这几个dijkstra思想的题目。太弱。。

#include 
#include <set>
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include <string>
#include 
#include 
#include 
#include 
#include 
#include 
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {
      return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 4100;
const int MAXM = 40005;
const double INF = 1e12;
struct node
{
    double x,y;
}src[MAXN];
double dis[MAXN];
bool vis[MAXN];
int N;

double dist(node a,node b)
{
    return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}

void dijkstra()
{
    memset(vis,false,sizeof(vis));
    for (int i = 0 ; i < MAXN ; i++) dis[i] = INF * 1.0;
    dis[1] = 0.0;
    for (int i = 1 ; i <= N ; i++)
    {
        double mincost = INF;
        int pos = - 1;
        for (int j = 1 ; j <= N ; j++)
        {
            if (!vis[j] && dis[j] < mincost)
            {
                mincost = dis[j];
                pos = j;
            }
        }
        if (pos == -1) return;
        vis[pos] = true;
        if (pos == 2) return;
        for (int j = 1 ; j <= N ; j++)
        {
            if (!vis[j] && dis[j] > max(dis[pos],dist(src[pos],src[j])))
                dis[j] = max(dis[pos],dist(src[pos],src[j]));
        }
    }
}

int main()
{
    int kase = 1;
    while (scanf("%d",&N) != EOF)
    {
        if (N == 0) break;
        for (int i = 1 ; i <= N ; i++) scanf("%lf%lf",&src[i].x,&src[i].y);
        dijkstra();
        printf("Scenario #%d\nFrog Distance = %.3f\n\n",kase++,dis[2]);
    }
    return 0;
}
View Code

POJ 1797 Heavy Transportation

一号点到N号点的合法路径中最小的边的最大值 ,这个实际就是最大生成树。直接kruskal很容易

这里还是要用下dijkstra和prim来区分一下。

下面这里是别人博客的一段话

在图论中,Prim算法是计算最小生成树的算法,而Dijkstra算法是计算最短路径的算法。二者看起来比较类似,因为假设全部顶点的集合是V,已经被挑选出来的点的集合是U,那么二者都是从集合V-U中不断的挑选权值最低的点加入U,那么二者是否等价呢?也就是说是否Dijkstra也可以计算出最小生成树而Prim也可以计算出从第一个顶点v0到其他点的最短路径呢?答案是否定的,否则就不必有两个算法了。

二者的不同之处在于“权值最低”的定义不同,Prim的“权值最低”是相对于U中的任意一点而言的,也就是把U中的点看成一个整体,每次寻找V-U中跟U的距离最小(也就是跟U中任意一点的距离最小)的一点加入U;而Dijkstra的“权值最低”是相对于v0而言的,也就是每次寻找V-U中跟v0的距离最小的一点加入U。

一个可以说明二者不等价的例子是有四个顶点(v0, v1, v2, v3)和四条边且边值定义为(v0, v1)=20, (v0, v2)=10, (v1, v3)=2, (v3, v2)=15的图,用Prim算法得到的最小生成树中v0跟v1是不直接相连的,也就是在最小生成树中v0v1的距离是v0->v2->v3->v1的距离是27,而用Dijkstra算法得到的v0v1的距离是20,也就是二者直接连线的长度。

第一份是dijkstra的

 

#include 
#include <set>
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include <string>
#include 
#include 
#include 
#include 
#include 
#include 
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {
      return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 1010;
int dis[MAXN][MAXN];
int N,M;
bool vis[MAXN];
int d[MAXN];

void dijkstra()
{
    memset(vis,false,sizeof(vis));
    memset(d,0,sizeof(d));
    for (int i = 1 ; i <= N ; i++) d[i] = dis[1][i];
    for (int i = 1 ; i <= N ; i++)
    {
        int maxcost = - 1;
        int pos = -1;
        for (int j = 1 ; j <= N ; j++)
        {
            if (!vis[j] && d[j] > maxcost)
            {
                maxcost = d[j];
                pos = j;
            }
        }
        if (pos == -1) return;
        if (pos == N) return;
        vis[pos] = true;
        for (int j = 1 ; j <= N ; j++)
        {
            if (!vis[j] && d[j] < min(d[pos],dis[pos][j]))
                d[j] = min(d[pos],dis[pos][j]);
        }
    }
}

int main()
{
    int kase = 1;
    int T;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d",&N,&M);
        memset(dis,0,sizeof(dis));
        for (int i = 0 ; i < M ; i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            dis[u][v] = dis[v][u] = w;
        }
        printf("Scenario #%d:\n",kase++);
        dijkstra();
        printf("%d\n\n",d[N]);
    }
    return 0;
}
View Code

第二份是prim的。仔细比对就发现差异

 

#include 
#include <set>
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include <string>
#include 
#include 
#include 
#include 
#include 
#include 
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {
      return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 1010;
const int INF = 0x3f3f3f3f;
int dis[MAXN][MAXN];
int N,M,ans;
bool vis[MAXN];
int d[MAXN];

void dijkstra()
{
    memset(vis,false,sizeof(vis));
    memset(d,0,sizeof(d));
    for (int i = 1 ; i <= N ; i++) d[i] = dis[1][i];
    d[1] = 0;
    vis[1] = true;
    ans = INF;
    for (int i = 1 ; i <= N ; i++)
    {
        int maxcost = - 1;
        int pos = -1;
        for (int j = 1 ; j <= N ; j++)
        {
            if (!vis[j] && d[j] > maxcost)
            {
                maxcost = d[j];
                pos = j;
            }
        }
        if (pos == -1) return;
        ans = min(ans,maxcost);
        if (pos == N) return;
        vis[pos] = true;
        for (int j = 1 ; j <= N ; j++)
        {
            if (!vis[j] && d[j] < dis[pos][j])
                d[j] = dis[pos][j];
        }
    }
}

int main()
{
    int kase = 1;
    int T;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d",&N,&M);
        memset(dis,0,sizeof(dis));
        for (int i = 0 ; i < M ; i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            dis[u][v] = dis[v][u] = w;
        }
        printf("Scenario #%d:\n",kase++);
        dijkstra();
        printf("%d\n\n",ans);
    }
    return 0;
}
View Code

POJ 3268 Silver Cow Party

有向图中从所有点到A点,再所有点从A点回到原本位置,问其中这些路径中最长的是哪个。

所有点从A回到原点是一次单元最短路即可。另一半怎么做。建反图,再从A求一次最短路,详情代码

 

#include 
#include <set>
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include <string>
#include 
#include 
#include 
#include 
#include 
#include 
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {
      return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 10010;
const int MAXM = 1000010;
const LL INF = 0x3f3f3f3f;
struct Edge
{
    int u,v,next;
    LL w;
}edge[MAXM],res[MAXN];
int head[MAXN],tot;
int N,M,X;

void init()
{
    memset(head,-1,sizeof(head));
    tot = 0;
}

void add_edge(int u,int v,LL w)
{
    edge[tot].u = u;
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].next = head[u];
    head[u] = tot++;
}

bool done[MAXN];
LL dis[5][MAXN];
struct heapnode
{
    LL val;
    int u;
    bool operator < (const heapnode &rhs) const
    {
        return val > rhs.val;
    }
};

void dijkstra(int s,int id)
{
    memset(dis[id],0x3f,sizeof(dis[id]));
    memset(done,false,sizeof(done));
    priority_queueq;
    dis[id][s] = 0;
    q.push((heapnode){dis[id][s],s});
    while (!q.empty())
    {
        heapnode x = q.top(); q.pop();
        int u = x.u;
        //printf("%d %d\n",u,dis[id][u]);
        if (done[u]) continue;
        done[u] = true;
        for (int i = head[u] ; i != -1 ; i = edge[i].next)
        {
            int v = edge[i].v;
            if (dis[id][v] > dis[id][u] + edge[i].w)
            {
                dis[id][v] = dis[id][u] + edge[i].w;
                q.push((heapnode){dis[id][v],v});
            }
        }
    }
}

void slove()
{
    //memset(dis,0x3f,sizeof(dis));
    for (int i = 0 ; i < M ; i++)
    {
        scanf("%d%d%I64d",&res[i].u,&res[i].v,&res[i].w);
    }
    init();
    for (int i = 0 ; i < M ; i++)
        add_edge(res[i].u,res[i].v,res[i].w);
    dijkstra(X,1);
    init();
    for (int i = 0 ; i < M ; i++)
        add_edge(res[i].v,res[i].u,res[i].w);
    dijkstra(X,2);
    LL ret = 0;
    for (int i = 1 ; i <= N ; i++)
    {
        if (i == X || dis[1][i] == INF || dis[2][i] == INF) continue;
        ret = max(ret,dis[1][i] + dis[2][i]);
    }
    printf("%I64d\n",ret);
}

int main()
{
    while (scanf("%d%d%d",&N,&M,&X) != EOF)
    {
        slove();
    }
    return 0;
}
View Code

 

POJ 1860 Currency Exchange
如何判断正环。这里2分代码。第一份spfa

#include 
#include <set>
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include <string>
#include 
#include 
#include 
#include 
#include 
#include 
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {
      return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 1010;
const int MAXM = 51000;
struct Edge
{
    int u,v,next;
    double rate,commission;
}edge[MAXM];
int head[MAXN],tot;
int N,M,S;
double val;

void init()
{
    memset(head,-1,sizeof(head));
    tot = 0;
}

void add_edge(int u,int v,double rate,double commission)
{
    edge[tot].u = u;
    edge[tot].v = v;
    edge[tot].rate = rate;
    edge[tot].commission = commission;
    edge[tot].next = head[u];
    head[u] = tot++;
}

double dis[MAXN];
bool inq[MAXN];
int cnt[MAXN];
queue<int>q;
bool spfa(int s)
{
    while (!q.empty()) q.pop();
    for (int i = 1 ; i <= N ; i++) dis[i] = -1;
    memset(inq,false,sizeof(inq));
    memset(cnt,0,sizeof(cnt));
    q.push(s);
    dis[s] = val;
    inq[s] = true;
    cnt[s] = 1;
    while (!q.empty())
    {
        int u = q.front(); q.pop();
        inq[u] = false;
        for (int i = head[u] ; i != -1 ; i = edge[i].next)
        {
            int v = edge[i].v;
            double rate = edge[i].rate;
            double commission = edge[i].commission;
            double price = (dis[u] - commission) * rate;
            if (price > dis[v])
            {
                dis[v] = price;
                if (!inq[v])
                {
                    q.push(v);
                    cnt[v]++;
                    inq[v] = true;
                }
                if (cnt[v] >= N) return true;
            }
        }
        if (dis[S] > val) return true;
    }
    return false;
}

int main()
{
    while (scanf("%d%d%d%lf",&N,&M,&S,&val) != EOF)
    {
        init();
        for (int i = 0 ; i < M ; i++)
        {
            int a,b;
            double rab,cab,rba,cba;
            scanf("%d%d%lf%lf%lf%lf",&a,&b,&rab,&cab,&rba,&cba);
            add_edge(a,b,rab,cab);
            add_edge(b,a,rba,cba);
        }
        bool flag = spfa(S);
        if (flag) puts("YES");
        else printf("NO\n");  
    }
    return 0;
}
View Code

第二份bellman_ford
注意迭代的次数为N-1,判断是否还正环和原本的一样、枚举边来松弛

#include 
#include <set>
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include <string>
#include 
#include 
#include 
#include 
#include 
#include 
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {
      return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 510;
const int MAXM = 510;
int N,M,S;
double val;
int tot;
double dis[MAXN];
struct Edge
{
    int u,v;
    double r,c;
}edge[MAXM];

bool bellman_ford()
{
    memset(dis,0,sizeof(dis));
    dis[S] = val;
    bool flag;
    for (int i = 1 ; i <= N - 1; i++)
    {
        flag = false;
        for (int j = 0 ; j < tot ; j++)
        {
            if (dis[edge[j].v] < (dis[edge[j].u] - edge[j].c) * edge[j].r)
            {
                dis[edge[j].v] = (dis[edge[j].u] - edge[j].c) * edge[j].r;
                flag = true;
            }
        }
        if (!flag) break;
    }

    for (int i = 0 ; i < tot ; i++)
    {
        if (dis[edge[i].v] < (dis[edge[i].u] - edge[i].c) * edge[i].r)
            return true;
    }
    return false;
}

int main()
{
    while (cin >> N >> M >> S >> val)
    {
        tot = 0;
        for (int i = 0 ; i < M ; i++)
        {
            int a,b;
            double rab,cab,rba,cba;
            cin >> a >> b >> rab >> cab >> rba >> cba;
            edge[tot].u = a;
            edge[tot].v = b;
            edge[tot].r = rab;
            edge[tot].c = cab;
            tot++;
            edge[tot].u = b;
            edge[tot].v = a;
            edge[tot].r = rba;
            edge[tot].c = cba;
            tot++;
        }
        if (bellman_ford()) puts("YES");
        else puts("NO");
    }
    return 0;

}
View Code

POJ 3259 Wormholes

判负环 同样2种代码

#include 
#include <set>
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include <string>
#include 
#include 
#include 
#include 
#include 
#include 
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {
      return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 1010;
const int MAXM = 50010;
const int INF = 0x3f3f3f3f;
struct Edge
{
    int u,v,w;
    int next;
}edge[MAXM];
int head[MAXN],tot;
int N,M,W;

void init()
{
    memset(head,-1,sizeof(head));
    tot = 0;
}

void add_edge(int u,int v,int w)
{
    edge[tot].u = u;
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].next = head[u];
    head[u] = tot++;
}

bool inq[MAXN];
queue<int>q;
int cnt[MAXN];
int dis[MAXN];
bool SPFA()
{
    while (!q.empty()) q.pop();
    for (int i = 1 ; i <= N ; i++)
    {
        dis[i] = INF;
        q.push(i);
        cnt[i] = 1;
        inq[i] = true;
    }
    while (!q.empty())
    {
        int u = q.front(); q.pop();
        inq[u] = false;
        for (int i = head[u] ; i != -1 ; i = edge[i].next)
        {
            int v = edge[i].v;
            if(dis[v] > dis[u] + edge[i].w)
            {
                dis[v] = dis[u] + edge[i].w;
                if (!inq[v])
                {
                    inq[v] = true;
                    q.push(v);
                    cnt[v]++;
                }
                if (cnt[v] >= N) return true;
            }
        }
    }
    return false;
}

int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
    {
        init();
        scanf("%d%d%d",&N,&M,&W);
        for (int i = 0 ; i < M ; i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            add_edge(u,v,w);
            add_edge(v,u,w);
        }
        for (int i = 0 ; i < W ; i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            add_edge(u,v,-w);
        }
        if (SPFA()) puts("YES");
        else puts("NO");
    }
    return 0;
}
View Code
#include 
#include <set>
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include <string>
#include 
#include 
#include 
#include 
#include 
#include 
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {
      return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 5010;
const int MAXM = 100010;
const int INF = 0x3f3f3f3f;
struct Edge
{
    int u,v,next;
    int w;
}edge[MAXM];
int tot;
int N,M,W;

int dis[MAXN];
bool bellman_ford()
{
    for (int i = 1 ; i <= N ; i++) dis[i] = INF;
    dis[1] = 0;
    for (int i = 1 ; i <= N - 1 ; i++)
    {
        for (int j = 0 ; j < tot ; j++)
        {
            int u = edge[j].u;
            int v = edge[j].v;
            int w = edge[j].w;
            if (dis[u] < INF && dis[v] > dis[u] + w)
            {
                dis[v] = dis[u] + w;
            }
        }
    }
    for (int i = 0 ; i < tot ; i++)
    {
        int u = edge[i].u;
        int v = edge[i].v;
        int w = edge[i].w;
        if (dis[u] < INF  && dis[v] > dis[u] + w)
            return true;
    }
    return false;
}

int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d%d",&N,&M,&W);
        tot = 0;
        for (int i = 0 ; i < M ; i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            edge[tot].u = u;
            edge[tot].v = v;
            edge[tot].w = w;
            tot++;
            edge[tot].v = u;
            edge[tot].u = v;
            edge[tot].w = w;
            tot++;
        }
        for (int i = 0 ; i < W ; i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            edge[tot].u = u;
            edge[tot].v = v;
            edge[tot].w = -w;
            tot++;
        }
        if (bellman_ford()) puts("YES");
        else puts("NO");
    }
    return 0;
}
View Code

POJ 1502 MPI Maelstrom

阅读题,floyd做

#include 
#include <set>
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include <string>
#include 
#include 
#include 
#include 
#include 
#include 
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {
      return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 110;
const int INF = 0x3f3f3f3f;
int dp[MAXN][MAXN];
int N;

void slove()
{
    for (int k = 1 ; k <= N ; k++)
    {
        for (int i = 1 ; i <= N; i++)
            for (int j = 1 ; j <= N ; j++)
        {
            dp[i][j] = min(dp[i][j],dp[i][k] + dp[k][j]);
        }
    }
    int ret = 0;
    for (int i = 2 ; i <= N ; i++)
        ret = max(dp[1][i],ret);
    printf("%d\n",ret);
}

int main()
{
    while (scanf("%d",&N) != EOF)
    {
        dp[1][1] = 0;
        for (int i = 2 ; i <= N ; i++)
        {
            dp[i][i] = 0;
            for (int j = 1 ; j <= i - 1 ; j++)
            {
                char tmp[10];
                scanf("%s",tmp);
                if (tmp[0] == 'x') dp[i][j] = INF;
                else dp[i][j] = atoi(tmp);
                dp[j][i] = dp[i][j];
            }
        }
        slove();
    }
    return 0;
}
View Code

POJ 3660 Cow Contest

题意:给出了一系列比赛结果。比如其中一场比赛描述为A.B 说明A的能力值大于B。问最后有几个人的能力值的排名可以根据这几场比赛完全确定。floyd传递闭包

#include 
#include <set>
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include <string>
#include 
#include 
#include 
#include 
#include 
#include 
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {
      return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 1010;
const int INF = 0x3f3f3f3f;
bool dp[MAXN][MAXN];
int main()
{
    int N,M;
    while (scanf("%d%d",&N,&M) != EOF)
    {
        memset(dp,false,sizeof(dp));
        for (int i = 1 ; i <= M ; i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            dp[u][v] = true;
        }
        for (int k = 1 ; k <= N ; k++)
            for (int i = 1 ; i <= N ; i++)
                for (int j = 1 ; j <= N ; j++)
                    if (dp[i][k] && dp[k][j]) dp[i][j] = true;
        int ret = 0 ;
        for (int i = 1 ; i <= N ; i++)
        {
            int cnt = 0;
            for (int j = 1 ; j <= N ; j++)
                cnt += dp[i][j] + dp[j][i];
            if (cnt == N - 1) ret++;
        }
        printf("%d\n",ret);
    }
    return 0;
}
View Code

POJ 2240 Arbitrage 

字符串map处理一下,然后直接floyd处理即可

#include 
#include <set>
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include <string>
#include 
#include 
#include 
#include 
#include 
#include 
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {
      return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 100;
const double eps = 1e-10;
double dp[MAXN][MAXN];
int N;
map<string,int>mp;
int main()
{
   // freopen("sample.txt","r",stdin);
    int kase = 1;
    while (scanf("%d",&N) != EOF)
    {
        if (N == 0) break;
        mp.clear();
        char str[100],tmp[100];
        int cas = 1;
        for (int i = 0 ; i < N ; i++)
        {
            scanf("%s",str);
            if (!mp[str]) mp[str] = cas++;
        }
        int M;
        for (int i = 0 ; i <= N ; i++)
        {
            for (int j = 0 ; j <= N ; j++)
                dp[i][j] = 0.0;
        }
        for (int i = 1 ; i <= N ; i++)
            dp[i][i] = 1.0;

        scanf("%d",&M);
        for (int i = 0 ; i < M ; i++)
        {
            double x;
            scanf("%s%lf%s",str,&x,tmp);
            int l = mp[str];
            int r = mp[tmp];
            dp[l][r] = max(dp[l][r],x);
        }
        for (int k = 1 ; k <= N ; k++)
        {
            for (int i = 1 ; i <= N ; i++)
                for (int j = 1 ; j <= N ; j++)
                dp[i][j] = max(dp[i][j],dp[i][k] * dp[k][j]);
        }
        double ret = 0.0;
        for (int i = 1 ; i <= N ; i++)
            ret = max(ret,dp[i][i]);
        if (ret - 1.0 > eps) printf("Case %d: Yes\n",kase++);
        else printf("Case %d: No\n",kase++);
    }
    return 0;
}
View Code

POJ 1511 Invitation Cards

题目大意:给出n个点和n条有向边,求所有点到源点1的来回最短路之和(保证每个点都可以往返源点1)

#include 
#include <set>
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include <string>
#include 
#include 
#include 
#include 
#include 
#include 
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {
      return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 1000100;
const int MAXM = 1000100;
const LL INF = 1e17;
int P,Q;
struct Edge
{
    int u,v,next;
    LL w;
}edge[MAXN];

struct heapnode
{
    LL val;
    int u;
    bool operator < (const heapnode & rhs) const
    {
        return val > rhs.val;
    }
};

struct Dijkstra
{
    int N,M;
    Edge edge[MAXM];
    int tot ,head[MAXN];
    LL dis[MAXN];
    bool done[MAXN];
    priority_queueq;

    void init(int n,int m)
    {
        memset(head,-1,sizeof(head));
        tot = 0;
        N = n;
        M = m;
    }

    void add_edge(int u,int v,LL w)
    {
        edge[tot].u = u;
        edge[tot].v = v;
        edge[tot].w = w;
        edge[tot].next = head[u];
        head[u] = tot++;
    }


    void dijkstra(int s)
    {
        for (int i = 0 ; i <= N ; i++) dis[i] = INF;
        while (!q.empty()) q.pop();
        memset(done,false,sizeof(done));
        dis[s] = 0;
        q.push((heapnode){dis[s],s});
        while (!q.empty())
        {
            heapnode x = q.top(); q.pop();
            int u = x.u;
            for (int i = head[u] ; i != -1 ; i = edge[i].next)
            {
                int v = edge[i].v;
                if (dis[v] > dis[u] + edge[i].w)
                {
                    dis[v] = dis[u] + edge[i].w;
                    q.push((heapnode){dis[v],v});
                }
            }
        }
    }
}first,second;

int main()
{
    int T,kase = 1;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d",&P,&Q);
        for (int i = 0 ; i < Q ; i++)
        {
            scanf("%d%d%I64d",&edge[i].u,&edge[i].v,&edge[i].w);
        }
        first.init(P,Q);
        for (int i = 0 ; i < Q ; i++)
        {
            first.add_edge(edge[i].u,edge[i].v,edge[i].w);
        }
        first.dijkstra(1);
        second.init(P,Q);
        for (int i = 0 ; i < Q ; i++)
        {
            second.add_edge(edge[i].v,edge[i].u,edge[i].w);
        }
        second.dijkstra(1);
        LL ret = 0;
        for (int i = 2 ; i <= P ; i++)
            ret = ret + first.dis[i] + second.dis[i];
        printf("%I64d\n",ret);
    }
    return 0;
}
View Code

POJ 3159 Candies
差分约束+SPFA

给n个人派糖果,给出m组数据,每组数据包含A,B,c  三个数,
意思是A的糖果数比B少的个数不多于c,即B的糖果数 - A的糖果数<= c 。
最后求n 比 1 最多多多少糖果。

贴一下kuangbin神的题解吧

【解题思路】
这是一题典型的差分约束题。不妨将糖果数当作距离,把相差的最大糖果数看成有向边AB的权值,
我们得到 dis[B]-dis[A]<=w(A,B)。看到这里,我们联想到求最短路时的松弛技术,
即if(dis[B]>dis[A]+w(A,B), dis[B]=dis[A]+w(A,B)。
即是满足题中的条件dis[B]-dis[A]<=w(A,B),由于要使dis[B] 最大,
所以这题可以转化为最短路来求。
这题如果用SPFA 算法的话,则需要注意不能用spfa+queue 来求,会TLE ,而是用 spfa + stack 

我自己直接dijkstra+优先队列是可以的。2个都贴一下
dijkstra

#include 
#include <set>
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include <string>
#include 
#include 
#include 
#include 
#include 
#include 
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {
      return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 30010;
const int MAXM = 150010;
const LL INF = 1e17;
int N,M;
struct Edge
{
    int u,v,next;
    LL w;
};

struct heapnode
{
    LL val;
    int u;
    bool operator < (const heapnode & rhs) const
    {
        return val > rhs.val;
    }
};

struct Dijksta
{
    int N,M;
    int head[MAXN],tot;
    Edge edge[MAXM];
    bool done[MAXN];
    LL dis[MAXN];
    priority_queueq;

    void init(int n,int m)
    {
        memset(head,-1,sizeof(head));
        tot = 0;
        N = n;
        M = m;
    }

    void add_edge(int u,int v,LL w)
    {
        edge[tot].u = u;
        edge[tot].v = v;
        edge[tot].w = w;
        edge[tot].next = head[u];
        head[u] = tot++;
    }

    void dijkstra(int s)
    {
        for (int i = 0 ; i <= N ; i++) dis[i] = INF;
        memset(done,false,sizeof(done));
        while (!q.empty()) q.pop();
        dis[s] = 0;
        q.push((heapnode){dis[s],s});
        while (!q.empty())
        {
            heapnode x = q.top(); q.pop();
            int u = x.u;
           // cout << u << " " << dis[u] << endl;
            if (done[u]) continue;
            done[u] = true;
            for (int i = head[u] ; i != -1 ; i = edge[i].next)
            {
                int v = edge[i].v;
                if (dis[v] > dis[u] + edge[i].w)
                {
                    dis[v] = dis[u] + edge[i].w;
                    q.push((heapnode){dis[v],v});
                }
            }
        }
    }
}src;

int main()
{
    while (scanf("%d%d",&N,&M) != EOF)
    {
        src.init(N,M);
        for (int i = 0 ; i < M ; i++)
        {
            int u,v;
            LL w;
            scanf("%d%d%I64d",&u,&v,&w);
            src.add_edge(u,v,w);
        }
        src.dijkstra(1);
        printf("%I64d\n",src.dis[N]);
    }
    return 0;
}
View Code

spfa + stack

#include 
#include <set>
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include <string>
#include 
#include 
#include 
#include 
#include 
#include 
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {
      return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 30010;
const int MAXM = 150010;
const int INF = 0x3f3f3f3f;
int head[MAXN],tot;
struct Edge
{
    int u,v,next;
    int w;
}edge[MAXM];
int N,M;

void init()
{
    memset(head,-1,sizeof(head));
    tot = 0;
}

void add_edge(int u,int v,int w)
{
    edge[tot].u = u;
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].next = head[u];
    head[u] = tot++;
}

bool inq[MAXN];
int Stack[MAXN + MAXN];
int top;
int dis[MAXN];
void Spfa(int s)
{
    int top = 0;
    for (int i = 1 ; i <= N ; i++) dis[i] = INF;
    memset(inq,false,sizeof(inq));
    inq[s] = true;
    top = 0;
    Stack[++top] = s;
    dis[s] = 0;
    while (top != 0)
    {
        int u = Stack[top];
        top--;
        inq[u] = false;
        for (int i = head[u]; i != -1 ; i = edge[i].next)
        {
            int v = edge[i].v;
            if (dis[v] > dis[u] + edge[i].w)
            {
                dis[v] = dis[u] + edge[i].w;
                if (!inq[v])
                {
                    inq[v] = true;
                    Stack[++top] = v;
                }
            }
        }
    }
}

int main()
{
    while (scanf("%d%d",&N,&M) != EOF)
    {
        init();
        for (int i = 0 ; i < M ; i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            add_edge(u,v,w);
        }
        Spfa(1);
        printf("%d\n",dis[N]);
    }
    return 0;
}
View Code

POJ 2502 Subway
读完提按照他说的来建图即可

我记得当时做的时候感觉超级NM坑。我不知道我自己的建图哪里WA了。反正就换一种别人的写法救过了。我真的不服。。

#include <set>
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include <string>
#include 
#include 
#include 
#include 
#include 
#include 
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {
      return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 330;
const int MAXM = MAXN * MAXN;
const double walkv = 10 * 1000.0 / 60.0;
const double subv = 40 * 1000.0 / 60.0;
const double INF = 1e17;
const double eps = 1e-10;
struct Edge
{
    int u,v,next;
    double w;
    bool walk;
};

struct heapnode
{
    double val;
    int u;
    bool operator < (const heapnode & rhs) const
    {
        return val > rhs.val;
    }
};

struct Dijkstra
{
    int N,M;
    bool done[MAXN];
    int head[MAXN],tot;
    Edge edge[MAXM];
    priority_queueq;
    double dis[MAXN];

    void init(int n,int m)
    {
        N = n;
        M = m;
        memset(head,-1,sizeof(head));
        tot = 0;
    }

    void add_edge(int u ,int v,double w,bool walk)
    {
        edge[tot].u = u;
        edge[tot].v = v;
        edge[tot].w = w;
        edge[tot].next = head[u];
        edge[tot].walk = walk;
        head[u] = tot++;
    }

    void dijkstra(int s)
    {
        memset(done,false,sizeof(done));
        while (!q.empty()) q.pop();
        for (int i = 0 ; i <= N ; i++) dis[i] = INF;
        dis[s] = 0.0;
        q.push((heapnode){dis[s],s});
        while (!q.empty())
        {
            heapnode  x = q.top(); q.pop();
            int u = x.u;
            if (done[u])continue;
            done[u] = true;
            for (int i = head[u] ; i != -1 ; i = edge[i].next)
            {
                int v = edge[i].v;
                double tmp;
                if (edge[i].walk)
                    tmp = dis[u] + edge[i].w / walkv ;
                else tmp = dis[u] + edge[i].w / subv;

                if (dis[v] > tmp)
                {
                    dis[v] = tmp;
                    q.push((heapnode){dis[v],v});
                }
            }
        }
    }
}src;

struct point
{
    double x,y;
    int id;
}st,ed,res[MAXN];
double map[MAXN][MAXN];
bool sub[MAXN][MAXN];
int cas,tot;


double dis(point &a, point &b)
{
    point p;
    p.x = a.x - b.x;
    p.y = a.y - b.y;
    return sqrt(p.x * p.x + p.y * p.y);
}

int main()
{
   // freopen("sample.txt","r",stdin);
    src.init(MAXN,MAXM);
    for (int i = 0 ; i < MAXN ; i++)
        for (int j = 0 ; j < MAXN ; j++) map[i][j] = -1.0;
    for (int i = 0 ; i < 2 ; i++) scanf("%lf%lf",&res[i].x,&res[i].y);
    tot = 2;
    point last,now;
    last.x = last.y = -1;
    while (scanf("%lf%lf", &now.x, &now.y) != EOF)
    {
        if (!(now.x == -1 && now.y == -1))
        {
            res[tot++] = now;
            if (!(last.x == -1 && last.y == -1))
            {
                src.add_edge(tot - 1,tot - 2 ,dis(res[tot - 1],res[tot - 2]),false);
                src.add_edge(tot - 2,tot - 1 ,dis(res[tot - 2],res[tot - 1]),false);
            }
        }
        last = now;
    }

    for (int i = 0 ; i < tot ; i++)
        for (int j = 0 ; j < tot ; j++)
        if (map[i][j] == -1)
    {
        map[i][j] = dis(res[i],res[j]);
        sub[i][j] = false;
        src.add_edge(i,j,map[i][j],true);
        src.add_edge(j,i,map[i][j],true);
    }
    src.dijkstra(1);
    printf("%.0f\n",src.dis[0]);
    return 0;
}
View Code

POJ 1062 昂贵的聘礼
读完提见图就行了

#include 
#include <set>
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include <string>
#include 
#include 
#include 
#include 
#include 
#include 
#define LL int
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {
      return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 310;
const int MAXM = MAXN * MAXN;
const int INF = 0x3f3f3f3f;
int M,N;
struct Edge
{
    int u,v,next;
    int w;
};

struct heapnode
{
    int val;
    int u;
    bool operator < (const heapnode & rhs) const
    {
        return val > rhs.val;
    }
};

struct Dijksta
{
    int N,M;
    int head[MAXN],tot;
    Edge edge[MAXM];
    bool done[MAXN];
    LL dis[MAXN];

    void init(int n,int m)
    {
        memset(head,-1,sizeof(head));
        tot = 0;
        N = n;
        M = m;
    }

    void add_edge(int u,int v,int w)
    {
        edge[tot].u = u;
        edge[tot].v = v;
        edge[tot].w = w;
        edge[tot].next = head[u];
        head[u] = tot++;
    }

    void dijkstra(int s)
    {
        for (int i = 0 ; i <= N ; i++) dis[i] = INF;
        dis[s] = 0;
      //  cout << " 122323" << endl;
        memset(done,false,sizeof(done));
       // cout << "sdsdsdw" << endl;
        priority_queueq;
      //  cout << "!213131" << endl;
        q.push((heapnode){dis[s],s});
        while (!q.empty())
        {
            heapnode x = q.top(); q.pop();
            int u = x.u;
          //  printf("%d %d\n",u,dis[u]);
            if (done[u]) continue;
            done[u] = true;
            for (int i = head[u] ; i != -1 ; i = edge[i].next)
            {
                int v = edge[i].v;
                if (dis[v] > dis[u] + edge[i].w)
                {
                    dis[v] = dis[u] + edge[i].w;
                    q.push((heapnode){dis[v],v});
                }
            }
        }
    }
}src;

struct node
{
    int P,L,X;
    int T[MAXN],V[MAXN];
}res[MAXN];

int main()
{
    while (scanf("%d%d",&M,&N) != EOF)
    {
        for (int i = 1 ; i <= N ; i++)
        {
            scanf("%d%d%d",&res[i].P,&res[i].L,&res[i].X);
            for (int j = 1 ; j <= res[i].X ; j++)
                scanf("%d%d",&res[i].T[j],&res[i].V[j]);
        }
        int ret = INF;
        for (int i = 1 ; i <= N ; i++)
        {
            src.init(MAXN,MAXM);
            for (int j = 1 ; j <= N ; j++) src.add_edge(0,j,res[j].P);
            int minlevel = res[i].L;
            for (int j = 1 ; j <= N ; j++)
            {
                if (res[j].L - minlevel > M || minlevel > res[j].L) continue;
                else
                {
                    //if (i == 2) cout << j << " " << res[j].L << endl;
                    for (int k = 1 ; k <= res[j].X ; k++)
                    {
                        if (res[res[j].T[k]].L - minlevel > M || minlevel > res[res[j].T[k]].L) continue;
                        src.add_edge(res[j].T[k],j,res[j].V[k]);
                    }
                }
            }
            //cout << "1111" << endl;
            src.dijkstra(0);
            ret = min(ret,src.dis[1]);
        }
        printf("%d\n",ret);
    }
    return 0;
}
View Code

POJ 1847 Tram

#include 
#include <set>
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include <string>
#include 
#include 
#include 
#include 
#include 
#include 
#define LL int
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {
      return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 110;
const int MAXM = MAXN * MAXN;
const int INF = 0x3f3f3f3f;
int N,M,A,B;
struct Edge
{
    int u,v,next;
    LL w;
};

struct heapnode
{
    LL val;
    int u;
    bool operator < (const heapnode & rhs) const
    {
        return val > rhs.val;
    }
};

struct Dijksta
{
    int N,M;
    int head[MAXN],tot;
    Edge edge[MAXM];
    bool done[MAXN];
    LL dis[MAXN];
    //priority_queueq;

    void init(int n,int m)
    {
        memset(head,-1,sizeof(head));
        tot = 0;
        N = n;
        M = m;
    }

    void add_edge(int u,int v,LL w)
    {
        edge[tot].u = u;
        edge[tot].v = v;
        edge[tot].w = w;
        edge[tot].next = head[u];
        head[u] = tot++;
    }

    void dijkstra(int s)
    {
        for (int i = 0 ; i <= N ; i++) dis[i] = INF;
        memset(done,false,sizeof(done));
        priority_queueq;
        dis[s] = 0;
        q.push((heapnode){dis[s],s});
        while (!q.empty())
        {
            heapnode x = q.top(); q.pop();
            int u = x.u;
           // cout << u << " " << dis[u] << endl;
            if (done[u]) continue;
            done[u] = true;
            for (int i = head[u] ; i != -1 ; i = edge[i].next)
            {
                int v = edge[i].v;
                if (dis[v] > dis[u] + edge[i].w)
                {
                    dis[v] = dis[u] + edge[i].w;
                    q.push((heapnode){dis[v],v});
                }
            }
        }
    }
}src;

int main()
{
    while (scanf("%d%d%d",&N,&A,&B) != EOF)
    {
        src.init(MAXN,MAXM);
        for (int i = 1 ; i <= N ; i++)
        {
            int cnt ;
            scanf("%d",&cnt);
            for (int j = 1 ; j <= cnt ; j++)
            {
                int x;
                scanf("%d",&x);
                if (j == 1) src.add_edge(i,x,0);
                else src.add_edge(i,x,1);
            }
        }
        src.dijkstra(A);
        printf("%d\n",src.dis[B] == INF ? -1 : src.dis[B]);
    }
    return 0;
}
View Code

题意:告诉n个点,每个点都有一个权值,A 到 B的时间等于 (val[b]-val[a])^3  都是单向边,可能存在负环,Q次询问,问从1到询问点的最短路,如果不可达或者点在负环上或者小于3,那么就输出? 否则输出最短路径值

标记负环上的点。

#include 
#include <set>
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include <string>
#include 
#include 
#include 
#include 
#include 
#include 
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {
      return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 210;
const int MAXM = MAXN * MAXN;
const int INF = 0x3f3f3f3f;
queue<int>q;
int N,M;
struct Edge
{
    int u,v,next;
    int w;
};

struct Spfa
{
    int N,M;
    bool inq[MAXN];
    int dp[MAXN],cnt[MAXN];
    int pre[MAXN];
    int head[MAXN],tot;
    int dis[MAXN];
    bool incir[MAXN];
    Edge edge[MAXM];

    void init(int n,int m)
    {
        N = n;
        M = m;
        tot = 0;
        memset(head,-1,sizeof(head));
        memset(cnt,0,sizeof(cnt));
    }

    void add_edge(int u,int v,int w)
    {
        edge[tot].u = u;
        edge[tot].v = v;
        edge[tot].w = w;
        edge[tot].next = head[u];
        head[u] = tot++;
    }

    void dfs(int pos)
    {
        incir[pos] = true;
        for (int i = head[pos] ; i != -1 ; i = edge[i].next)
        {
            int v = edge[i].v;
            if (!incir[v])
                dfs(v);
        }
    }

    void spfa(int s)
    {
        memset(incir,false,sizeof(incir));
        memset(inq,false,sizeof(inq));
        for (int i = 1 ; i <= N ; i++) dis[i] = INF;
        while (!q.empty()) q.pop();
        q.push(s);
        dis[s] = 0;
        cnt[s] = 1;
        inq[s] = true;
        while (!q.empty())
        {
            int u = q.front(); q.pop();
            inq[u] = false;
            for (int i = head[u] ; i != -1 ; i = edge[i].next)
            {
                int v = edge[i].v;
                if (incir[v]) continue;
                if (dis[v] > dis[u] + edge[i].w)
                {
                    dis[v] = dis[u] + edge[i].w;
                    if (!inq[v])
                    {
                        inq[v] = true;
                        cnt[v]++;
                        q.push(v);
                        if (cnt[v] >= N) dfs(v);
                    }
                }
            }
        }
    }
}src;

int res[MAXN];

int main()
{
   // freopen("sample.txt","r",stdin);
    int T,kase = 1 ;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&N);
        for (int i = 1 ; i <= N ; i++) scanf("%d",&res[i]);
        scanf("%d",&M);
        src.init(N,M);
        for (int i = 1 ; i <= M ; i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            src.add_edge(u,v,(res[v] - res[u]) * (res[v] - res[u]) *
                                (res[v] - res[u]));
        }
        src.spfa(1);
        printf("Case %d:\n",kase++);
        int q;
        scanf("%d",&q);
        while (q--)
        {
            int u;
            scanf("%d",&u);
            if (src.incir[u] || src.dis[u] < 3 || src.dis[u] >= INF)
                printf("?\n");
            else printf("%d\n",src.dis[u]);
        }
    }
    return 0;
}
View Code

 HDU 4725 The Shortest Path in Nya Graph

总共3*N个点,1-N个点,N + 1 ---- N + N + N 这几个点分别是拆点的点。

至于为什么要拆点,注意到在一层的点不一定能直接到达。参考数据

3 0 1

1 1 1 ans = -1;

所有层拆点分为前向点 后项点。 见图为点连层前向点,层层之间后连前,具体看代码

#include 
#include <set>
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include <string>
#include 
#include 
#include 
#include 
#include 
#include 
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {
      return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 300010;
const int MAXM = MAXN * 20;
const int INF = 0x3f3f3f3f;
struct Edge
{
    int u,v,w;
    int next;
}edge[MAXM];
int head[MAXN],tot;

void init()
{
    memset(head,-1,sizeof(head));
    tot = 0;
}

void add_edge(int u,int v,int w)
{
    edge[tot].u = u;
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].next = head[u];
    head[u] = tot++;
}

struct heapnode
{
    int val,u;
    bool operator < (const heapnode &rhs) const
    {
        return val > rhs.val;
    }
};

priority_queueq;
bool done[MAXN];
int dis[MAXN];

void dijkstra(int s)
{
    memset(done,false,sizeof(done));
    while (!q.empty()) q.pop();
    memset(dis,0x3f,sizeof(dis));
    dis[s] = 0;
    heapnode tmp;
    tmp.val = dis[s];
    tmp.u = s;
    q.push(tmp);
    while (!q.empty())
    {
        heapnode x = q.top(); q.pop();
        int u = x.u;
        if (done[u]) continue;
        done[u] = true;
        for (int i = head[u] ; i != -1 ; i = edge[i].next)
        {
            int v = edge[i].v;
            if (dis[v] > dis[u] + edge[i].w)
            {
                dis[v] = dis[u] + edge[i].w;
                heapnode tmp;
                tmp.val = dis[v];
                tmp.u = v;
                q.push(tmp);
            }
        }
    }
}

int N,M,C;
int main()
{
   //freopen("Sample.txt","r",stdin);
    int T,kase = 1;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d%d",&N,&M,&C);
        init();
        for (int i = 1 ; i <= N ; i++)
        {
            int x;
            scanf("%d",&x);
            add_edge(i,N + x,0);
            add_edge(N + N + x,i,0);
        }
        for (int i = 1 ; i < N ; i++)
        {
            add_edge(N + i,N + N + i + 1,C);
            add_edge(N + i + 1,N + N + i,C);
        }
        for (int i = 0 ; i < M ; i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            add_edge(u,v,w);
            add_edge(v,u,w);
        }
       // for (int i = 0 ; i < tot ; i++)
          //  printf("%d %d %d\n",edge[i].u,edge[i].v,edge[i].w);
        dijkstra(1);
        if (dis[N] == INF) dis[N] = -1;
        printf("Case #%d: %d\n",kase++,dis[N]);

    }
    return 0;
}
View Code

HDU 3416 Marriage Match IV

最短路的所有边只能走一次。直接最短路+最大流

这里唯一的问题就是最短路树是什么样子的。有向图和无向图的设置不太一样。前面连通图专题里有无向图的这里有向图的我相关的已经注释区分了

#include 
#include <set>
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include <string>
#include 
#include 
#include 
#include 
#include 
#include 
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {
      return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 1010;
const int MAXM = 200010;
const int INF = 0x3f3f3f3f;
struct Edge
{
    int u,v,w;
    int next;
    int id;
    bool cut;
};

struct heapnode
{
    int val,u;
    bool operator < (const heapnode &rhs) const
    {
        return val > rhs.val;
    }
};

priority_queueq;

struct Dijkstra
{
    int N,M;
    int dis[MAXN];
    bool done[MAXN];
    int head[MAXN],tot;
    Edge edge[MAXM];

    void init(int n)
    {
        memset(head,-1,sizeof(head));
        tot = 0;
        N = n;
    }

    void add_edge(int u,int v,int w,int id)
    {
        edge[tot].u = u;
        edge[tot].v = v;
        edge[tot].w = w;
        edge[tot].id = id;
        edge[tot].next = head[u];
        head[u] = tot++;
    }

    void dijkstra(int s)
    {
        memset(done,false,sizeof(done));
        for (int i = 0 ; i <= N ; i++) dis[i] = INF;
        dis[s] = 0;
        while (!q.empty()) q.pop();
        q.push((heapnode){dis[s],s});
        while (!q.empty())
        {
            heapnode x = q.top(); q.pop();
            int u = x.u;
           // cout << u << " " << dis[u] << endl ;
            if (done[u]) continue;
            done[u] = true;
            for (int i = head[u] ; i != -1 ; i = edge[i].next)
            {
                int v = edge[i].v;
                if (dis[v] > dis[u] + edge[i].w)
                {
                    dis[v] = dis[u] + edge[i].w;
                    q.push((heapnode){dis[v],v});
                }
            }
        }
    }

}St,Ted;


struct Edge2
{
    int u,v,next;
    int cap,flow;
}edge[MAXM];
int head[MAXN],tot;
int gap[MAXN],dep[MAXN],cur[MAXN];

void init()
{
    memset(head,-1,sizeof(head));
    tot = 0;
}

void add_edge(int u,int v,int cap,int rcap = 0)
{
    edge[tot].u = u;
    edge[tot].v = v;
    edge[tot].cap = cap;
    edge[tot].flow = 0;
    edge[tot].next = head[u];
    head[u] = tot++;

    edge[tot].u = v;
    edge[tot].v = u;
    edge[tot].cap = rcap;
    edge[tot].flow = 0;
    edge[tot].next = head[v];
    head[v] = tot++;
}

int Q[MAXN];
void BFS(int st,int ed)
{
    memset(dep,-1,sizeof(dep));
    memset(gap,0,sizeof(gap));
    gap[0] = 1;
    int front = 0 ,rear = 0;
    dep[ed] = 0;
    Q[rear++] = ed;
    while (front < rear)
    {
        int u = Q[front++];
        for (int i = head[u] ; i != -1 ; i = edge[i].next)
        {
            int v = edge[i].v;
            if (dep[v] != -1) continue;
            Q[rear++] = v;
            dep[v] = dep[u] + 1;
            gap[dep[v]]++;
        }
    }
}

int S[MAXN];
int sap(int st,int ed,int N)
{
    BFS(st,ed);
    memcpy(cur,head,sizeof(head));
    int top = 0;
    int u = st;
    int ans = 0;
    while (dep[st] < N)
    {
        if (u == ed)
        {
            int Min = INF;
            int inser;
            for (int i = 0 ; i < top ; i++)
            {
                if (Min > edge[S[i]].cap - edge[S[i]].flow)
                {
                    Min = edge[S[i]].cap - edge[S[i]].flow;
                    inser = i;
                }
            }
            for (int i = 0 ; i < top ; i++)
            {
                edge[S[i]].flow += Min;
                edge[S[i] ^ 1].flow -=Min;
            }
            ans += Min;
            top = inser;
            u = edge[S[top] ^ 1].v;
            continue;
        }
        bool flag = false;
        int v;
        for (int i = cur[u] ; i != -1 ; i = edge[i].next)
        {
            v = edge[i].v;
            if (edge[i].cap - edge[i].flow && dep[v] + 1 == dep[u])
            {
                flag = true;
                cur[u] = i;
                break;
            }
        }
        if(flag)
        {
            S[top++] = cur[u];
            u = v;
            continue;
        }
        int Min = N;
        for (int i = head[u] ; i != -1 ; i = edge[i].next)
        {
            if (edge[i].cap - edge[i].flow && dep[edge[i].v] < Min)
            {
                Min = dep[edge[i].v];
                cur[u] = i;
            }
        }
        gap[dep[u]]--;
        if (!gap[dep[u]]) return ans;
        dep[u] = Min + 1;
        gap[dep[u]]++;
        if (u != st) u = edge[S[--top] ^ 1].v;
    }
    return ans;
}

int u[MAXM],v[MAXM],w[MAXM];
int A,B,N,M;
int main()
{
   // freopen("sample.txt","r",stdin);
    int kase;
    scanf("%d",&kase);
    while (kase--)
    {
        scanf("%d%d",&N,&M);
        St.init(N);
        Ted.init(N);
        init();
        for (int i = 0 ; i < M ; i++)
        {
            scanf("%d%d%d",&u[i],&v[i],&w[i]);
            St.add_edge(u[i],v[i],w[i],i + 1);
            //St.add_edge(v[i],u[i],w[i],i + 1);
            //Ted.add_edge(u[i],v[i],w[i],i + 1);
            Ted.add_edge(v[i],u[i],w[i],i + 1);
        }
        scanf("%d%d",&A,&B);
        St.dijkstra(A);
       /* if (St.dis[B] == INF)
        {
            puts("0");
            continue;
        }
        */
        Ted.dijkstra(B);
        for (int i = 0 ; i < M ; i++)
        {
            int tu = u[i];
            int tv = v[i];
            int tw = w[i];
            if (tu == tv) continue;
            if ((St.dis[tu] + tw == St.dis[tv] && Ted.dis[tv] + tw == Ted.dis[tu])
                ||(St.dis[tv] + tw == St.dis[tu] && Ted.dis[tu] + tw == Ted.dis[tv]))
            {
                add_edge(tu,tv,1);
            }
        }
        printf("%d\n",sap(A,B,N + 5));

    }
    return 0;
}
View Code

HDU 4370  0 or 1
看bin神题解吧。此题太神了。

这里代码主要记录一下如何求闭环。循环队列等问题

复制的

转换思维的题啊,由一道让人不知如何下手的题,转换为了最短路 基本思路就是把矩阵看做一个图,图中有n个点,1号点出度为1, n号点入度为1,其它点出度和入度相等,路径长度都是非负数,

等价于一条从1号节点到n号节点的路径,故Xij=1表示需要经 过边(i,j),代价为Cij。Xij=0表示不经过边(i,j)。注意到Cij非负 且题目要求总代价最小,因此最优答案的路径一定可以对应一条简单路径。

最终,我们直接读入边权的邻接矩阵,跑一次1到n的最短路即可,记最短路为path。

漏如下的情况B: 从1出发,走一个环(至少经过1个点,即不能 是自环),回到1;从n出发,走一个环(同理),回到n。 也就是1和n点的出度和入度都为1,其它点的出度和入度为0.

由于边权非负,于是两个环对应着两个简单环。

因此我们可以从1出发,找一个最小花费环,记代价为c1, 再从n出发,找一个最小花费环,记代价为c2。 (只需在最短路算法更新权值时多加一条记录即可:if(i==S) cir=min(cir,dis[u]+g[u][i]))

故最终答案为min(path,c1+c2) */ /* 本程序用SPFA来完成最短路。 但是由于要计算从出发点出发的闭环的路径长度。 所以要在普通SPFA的基础上做点变化。

就是把dist[start]设为INF。同时一开始并不是让出发点入队,而是让 出发点能够到达的点入队。

代码:

 

#include 
#include <set>
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include <string>
#include 
#include 
#include 
#include 
#include 
#include 
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {
      return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 350;
const int INF = 0x3f3f3f3f;
int cost[MAXN][MAXN];
int dist[MAXN];
int que[MAXN];
bool inq[MAXN];

void spfa(int s,int n)
{
    int front = 0,rear = 0;
    for (int v = 1 ; v <= n ; v++)
    {
        if (v == s)//由于要找start的闭环,所以dist[start]设为INF,且不入队
        {
            dist[v] = INF;
            inq[v] = false;
        }
        else if(cost[s][v] != INF)
        {
            dist[v] = cost[s][v];
            que[rear++] = v;
            inq[v] = true;
        }
        else//即dist[start][v]==INF情况,对本题没有这种情
        {
            dist[v] = INF;
            inq[v] = false;
        }
    }
    while (front != rear)//注意这个条件是不等,因为是循环队列
    {
        int u = que[front++];
        for (int v = 1 ; v <= n ; v++)
        {
            if (dist[v] > dist[u] + cost[u][v])
            {
                dist[v] = dist[u] + cost[u][v];
                if (!inq[v])
                {
                    que[rear++] = v;
                    if (rear >= MAXN) rear = 0;
                    inq[v] = true;
                }
            }
        }
        inq[u] = false;
        if (front >= MAXN) front = 0;
    }

}

int main()
{
    int N;
    while (scanf("%d",&N) != EOF)
    {
        memset(cost,0x3f,sizeof(cost));
        for (int i = 1 ; i <= N ; i++)
            for (int j = 1 ; j <= N ; j++)
                scanf("%d",&cost[i][j]);
        spfa(1,N);
        int ans = dist[N];//1到n的最短路
        int cmp = dist[1];//1的自环长度
        spfa(N,N);
        cmp += dist[N];//N的自环长度
        printf("%d\n",min(ans,cmp));
    }
    return 0;
}
View Code

POJ 3169 Layout

查分约束变换一下不等式就行了

对那ML个条件

d[y] - d[x] <= w -> d[x] + w >= d[y]

对那MD个条件

d[y] - d[x] >= w -> d[y] + (-w) >= d[x] 

对于一个不等式 d[u] + w >= d[v] 我们可以加边(u, v , w) 因为松弛操作

2份代码

#include 
#include <set>
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include <string>
#include 
#include 
#include 
#include 
#include 
#include 
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {
      return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 2010;
const int MAXM = 20010;
const int INF = 0x3f3f3f3f;
int N,ML,MD;
bool inq[MAXN];
int cnt[MAXN];
struct Edge
{
    int u,v,w;
    int next;
}edge[MAXM];
int head[MAXN],tot;

void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
}

void add_edge(int u,int v,int w)
{
    edge[tot].u = u;
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].next = head[u];
    head[u] = tot++;
}

queue<int>q;
int dis[MAXN];

bool spfa(int s,int n)
{
    memset(inq,false,sizeof(inq));
    memset(cnt,0,sizeof(cnt));
    memset(dis,0x3f,sizeof(dis));
    while(!q.empty()) q.pop();
    q.push(s);
    dis[s] = 0;
    inq[s] = true;
    cnt[s] = 1;
    while (!q.empty())
    {
        int u = q.front(); q.pop();
        inq[u] = false;
        //printf("%d %d\n",u,dis[u]);
        for (int i = head[u] ; i != -1 ; i = edge[i].next)
        {
            int v = edge[i].v;
            if (dis[v] > dis[u] + edge[i].w)
            {
                dis[v] = dis[u] + edge[i].w;
                if (!inq[v])
                {
                    inq[v] = true;
                    q.push(v);
                    cnt[v]++;
                }
                if(cnt[v] >= n) return true;
            }
        }
    }
    return false;
}

int main()
{
    while (scanf("%d%d%d",&N,&ML,&MD) != EOF)
    {
        init();
        for (int i = 0 ; i < ML ; i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            if(u > v) swap(u,v);
            add_edge(u,v,w);
        }
        for (int i = 0 ; i < MD ; i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            if (u < v) swap(u,v);
            add_edge(u,v,-w);
        }
       // for (int i = 0 ; i < tot ; i++) printf("%d %d %d\n",edge[i].u,edge[i].v,edge[i].w);
        if (spfa(1,N)) puts("-1");
        else if (dis[N] >= INF) puts("-2");
        else printf("%d\n",dis[N]);
    }
    return 0;
}
View Code
#include 
#include <set>
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include <string>
#include 
#include 
#include 
#include 
#include 
#include 
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {
      return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 2010;
const int MAXM = 20010;
const int INF = 0x3f3f3f3f;
int N,ML,MD;
int dis[MAXN];
struct Edge
{
    int u,v,w;
    int next;
}edge[MAXM];
int tot;


bool bellman_ford(int s,int n)
{
    memset(dis,0x3f,sizeof(dis));
    dis[s] = 0;
    for (int i = 1 ; i <= n - 1 ; i++)
    {
        for (int j = 0 ; j < tot ; j++)
        {
            int u = edge[j].u;
            int v = edge[j].v;
            if (dis[v] > dis[u] + edge[j].w)
            {
                dis[v] = dis[u] + edge[j].w;
            }
           // printf("%d %d %d %d\n",u,v,dis[u],edge[j].w);
        }
    }
    for (int j = 0 ; j < tot ; j++)
    {
        if (dis[edge[j].v] > dis[edge[j].u] + edge[j].w)
            return true;
    }
    return false;
}

int main()
{
    while (scanf("%d%d%d",&N,&ML,&MD) != EOF)
    {
        tot = 0;
        for (int i = 0 ; i < ML ; i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            if(u > v) swap(u,v);
            edge[tot].u = u;
            edge[tot].v = v;
            edge[tot].w = w;
            tot++;
        }
        for (int i = 0 ; i < MD ; i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            if (u < v) swap(u,v);
            edge[tot].u = u;
            edge[tot].v = v;
            edge[tot].w = -w;
            tot++;
        }
        //for (int i = 0 ; i < tot ; i++) printf("%d %d %d\n",edge[i].u,edge[i].v,edge[i].w);
        if (bellman_ford(1,N)) puts("-1");
        else if (dis[N] >= INF) puts("-2");
        else printf("%d\n",dis[N]);
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/Commence/p/4890201.html

你可能感兴趣的:(数据结构与算法)