[kuangbin带你飞]专题四 最短路练习

/*
0 or 1
HDU - 4370
https://cn.vjudge.net/problem/HDU-4370#author=0
题意: 给你一个n*n矩阵,让你新建一个只有0和1的n*n矩阵,满足新建的这个矩阵与原来那个矩阵对应位置相乘最小,
      新建的这个矩阵满足一下条件
      1.X12+X13+...X1n=1
      2..X1n+X2n+...Xn-1n=1
      3.∑Xki =∑Xij
输入:n 和 n*n的矩阵
样例输入:
      4
      1 2 4 10
      2 0 1 1
      2 2 0 5
      6 3 1 2
样例输出:
      3
思路:
1.X12+X13+...X1n=1 于是1号节点的出度为1
2..X1n+X2n+...Xn-1n=1 于是n号节点的入度为1
3.∑Xki =∑Xij 于是2~n-1号节点的入度必须等于出度
所以建图,跑最短路,或者是最小环
*/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define maxn 310
#define INF 0x3f3f3f3f
int mp[maxn][maxn];
int dis[maxn];
int n;
void spfa(int st){
  queue<int> q;
  for(int i=1;i<=n;i++){
    if(i==st){
      dis[i]=INF;
    }else{
      dis[i]=mp[st][i];
      q.push(i);
    }
  }
  while(!q.empty()){
    int u=q.front();
    q.pop();
    for(int i=1;i<=n;i++){
      if(dis[i]>dis[u]+mp[u][i]){
        dis[i]=dis[u]+mp[u][i];
        q.push(i);
      }
    }
  }
}
int main(){
  while(~scanf("%d", &n)){
    for(int i=1;i<=n;i++){
      for(int j=1;j<=n;j++){
        scanf("%d", &mp[i][j]);
      }
    }
    spfa(1);
    int ans=dis[n];
    int c1=dis[1];
    spfa(n);
    int c2=dis[n];
    printf("%d\n", min(ans,c1+c2));
  }
  return 0;
}

/*
Arbitrage
POJ - 2240
https://cn.vjudge.net/problem/POJ-2240#author=0
题意: 通过货币汇率的差异来赚钱
输入: 货币种类的数目n
      下面n行是货币名称
      货币交换的数目t
      下面t行是 u -> v w
      n为0时结束
样例输入:
      3
      USDollar
      BritishPound
      FrenchFranc
      3
      USDollar 0.5 BritishPound
      BritishPound 10.0 FrenchFranc
      FrenchFranc 0.21 USDollar

      3
      USDollar
      BritishPound
      FrenchFranc
      6
      USDollar 0.5 BritishPound
      USDollar 4.9 FrenchFranc
      BritishPound 10.0 FrenchFranc
      BritishPound 1.99 USDollar
      FrenchFranc 0.09 BritishPound
      FrenchFranc 0.19 USDollar

      0
样例输出:
      Case 1: Yes
      Case 2: N
解法:
map 映射 + spfa
*/
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <map>
#include <iostream>
using namespace std;
#define maxn 100000
#define INF 0x3f3f3f
map<string,int> mp;
struct node{
  int u,v;
  double w;
  int next;
}edge[maxn];
int head[maxn];
double dis[maxn];
string a,b;
int cnt,n,t;
int B=1;
void init(){
  memset(dis,0,sizeof dis);
  memset(head,-1,sizeof head);
  cnt=0;
}
void add(int u,int v,double w){
  edge[cnt].w=w;
  edge[cnt].u=u;
  edge[cnt].v=v;
  edge[cnt].next=head[u];
  head[u]=cnt++;
}
bool spfa(int B){
  dis[B]=1;
  queue<int> q;
  q.push(B);
  while(!q.empty()){
    int u=q.front();
    q.pop();
    for(int i=head[u];~i;i=edge[i].next){
      if(dis[edge[i].v]<dis[u]*edge[i].w){
        dis[edge[i].v]=dis[u]*edge[i].w;
        if(dis[B]>1) return true;
        q.push(edge[i].v);
      }
    }
  }
  return false;
}
int main(){
  int T=1;
  while(~scanf("%d", &n)&&n){
    init();
    for(int i=1;i<=n;i++){
      cin>>a;
      mp[a]=i;
    }
    scanf("%d", &t);
    double w;
    for(int i=0;i<t;i++){
      cin>>a>>w>>b;
      add(mp[a],mp[b],w);
    }
    printf("Case %d: ", T++);
    if(spfa(B)) printf("Yes\n");
    else printf("No\n");
  }
}

/*
Candies
POJ - 3159
https://cn.vjudge.net/problem/POJ-3159#author=xym000
题意:求最大的差异
输入:n个孩子,t个关系
      a相信b永远不会比他自己多c个糖果
样例输入:
      2 2
      1 2 5
      2 1 4
样例输出;
      5
解法:
让第一个孩子拿到的糖果为0,然后跑一边spfa,保证所以的孩子能满足他们之间的关系,然后输出dis[n]
注意:
后台数据卡queue但是不卡stack
*/
#include <cstring>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <stack>
#include <queue>
using namespace std;
#define maxn 30010
#define maxm 150010
#define INF 0x3f3f3f
struct node{
  int u,v,w;
  int next;
}edge[maxm];
int head[maxn];
int dis[maxn];
bool color[maxn];
int cnt,n,t;
void init(){
  memset(head,-1,sizeof head);
  memset(dis,INF,sizeof dis);
  cnt=0;
}
void add(int u,int v,int w){
  edge[cnt].u=u;
  edge[cnt].v=v;
  edge[cnt].w=w;
  edge[cnt].next=head[u];
  head[u]=cnt++;
}
void spfa(){
  memset(color,true,sizeof color);
  stack<int> q;
  dis[1]=0;
  q.push(1);
  color[1]=false;
  while(!q.empty()){
    int u=q.top();
    q.pop();
    color[u]=true;
    for(int i=head[u];~i;i=edge[i].next){
      if(dis[edge[i].v]>dis[u]+edge[i].w){
        dis[edge[i].v]=dis[u]+edge[i].w;
        if(color[edge[i].v]){
          q.push(edge[i].v);
          color[edge[i].v]=false;
        }
      }
    }
  }
  return;
}
int main(){
  while(~scanf("%d %d", &n, &t)){
    init();
    int u,v,w;
    for(int i=0;i<t;i++){
      scanf("%d %d %d", &u, &v, &w);
      add(u,v,w);
    }
    spfa();
    printf("%d\n", dis[n]);
  }
  return 0;
}

/*
Cow Contest
POJ - 3660
https://cn.vjudge.net/problem/POJ-3660#author=freeloop
题意 :从n的同学参加比赛,有m条实力信息,问最后有多少名同学可以确定他的排名,保证合法
输入 :n   m
      A > B
样例输入:
      5 5
      4 3
      4 2
      3 2
      1 2
      2 5
样例输出:
      2
解法:
(Floyed-Warshall)传递闭包
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
#define maxn 110
#define INF 0x3f3f3f
int mp[maxn][maxn];
int n,t;
void init(){
  memset(mp,0,sizeof mp);
}
int main(){
  scanf("%d %d", &n, &t);
  init();
  int u,v;
  for(int i=0;i<t;i++){
    scanf("%d %d", &u, &v);
    mp[u][v]=1;
  }
  for(int k=1;k<=n;k++){
    for(int i=1;i<=n;i++){
      for(int j=1;j<=n;j++){
          if(mp[i][k]&&mp[k][j]) mp[i][j]=1;
      }
    }
  }
  int ans=0;
  for(int i=1;i<=n;i++){
    int j;
    for(j=1;j<=n;j++){
      if(i==j) continue;
      if(!mp[i][j]&&!mp[j][i]) break;
    }
    if(j>n) ans++;
  }
  printf("%d\n", ans);
  return 0;
}

/*
Currency Exchange
POJ - 1860
https://cn.vjudge.net/problem/POJ-1860
题意: 兑换货币
      每个地方倒每个地方的兑换汇率和佣金都不一样
      他要是回到出发点时自己的钱增加了,就输出YES否NO
输入:
      第一行是  : 点个数,边个数,出发点,开始的钱
      下面m行是 : 从u->v u->v的汇率 u->v的佣金 v->u的汇率 v->u的佣金
样例输入:
      3 2 1 20.0
      1 2 1.00 1.00 1.00 1.00
      2 3 1.10 1.00 1.10 1.00
样例输出:
      YES
解法:
      直接跑spfa要是发现开始的价值增加了,那就是YES否则NO
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<iostream>
using namespace std;
#define INF 0x3f3f3f
#define maxn 10010
struct node{
  double wa, a;
  int e;
  int next;
}edge[maxn];
int cnt;
int head[maxn];
int n,t,lei;
double num;
void init(){
  memset(head,0,sizeof head);
  cnt=1;
}
void add(int u,int v,double a, double wa){
  edge[cnt].wa=wa;
  edge[cnt].a=a;
  edge[cnt].e=v;
  edge[cnt].next=head[u];
  head[u]=cnt++;
}
bool spfa(int sb){
  queue<int> q;
  bool color[maxn];
  double d[maxn];
  memset(d,0,sizeof d);
  memset(color,true,sizeof color);
  q.push(sb);
  d[sb]=num;
  color[sb]=false;
  while(!q.empty()){
    int st=q.front();
    q.pop();
    color[st]=true;
    for(int i=head[st];i!=0;i=edge[i].next){
      if((d[st]-edge[i].wa)*edge[i].a>d[edge[i].e]){
        d[edge[i].e]=(d[st]-edge[i].wa)*edge[i].a;
            if(d[sb]>num) return true;
        if(color[edge[i].e]){
            q.push(edge[i].e);
            color[edge[i].e]=false;
        }
      }
    }
  }
  return false;
}
int main(){
  scanf("%d %d %d %lf", &n, &t, &lei, &num);
  init();
  int u,v;
  double a,b,wa,wb;
  for(int i=0;i<t;i++){
    scanf("%d %d %lf %lf %lf %lf", &u, &v, &a, &wa, &b, &wb);
    add(u, v, a, wa);
    add(v, u, b, wb);
  }
  if(spfa(lei)) printf("YES\n");
  else printf("NO\n");
  return 0;
}

/*
Extended Traffic
LightOJ - 1074
https://cn.vjudge.net/problem/LightOJ-1074
题意:每条街道的拥挤度P(x),街a到街b的时间是(p(b)-p(a))^3,找最短路,若无法到达或结果小于3,输出?
输入:T组样例
      城市个数
      1到n的繁荣度
      城市中的道路数量
      单向 u->v
      q个查询
      1到qi
样例输入:
      2
      5
      6 7 8 9 10
      6
      1 2
      2 3
      3 4
      1 5
      5 4
      4 5
      2
      4
      5
      2
      10 10
      1
      1 2
      1
      2
样例输出:
      Case 1:
      3
      4
      Case 2:
      ?
解法:
SPFA判负环
*/

#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <iostream>
#include <cmath>
using namespace std;
#define maxt 1000000
#define maxn 1000
#define INF 0x3f3f3f3f
struct node{
  int u,v,w;
  int next;
}edge[maxt];
int head[maxn];
int dis[maxn];
int d[maxn];
int color[maxn];
int cnt,n,t;
void init(){
  memset(head,-1,sizeof head);
  memset(dis,INF,sizeof dis);
  memset(color,0,sizeof color);
  memset(edge,0,sizeof edge);
  memset(d,0,sizeof d);
  cnt=0;
}
void add(int u,int v,int w){
  edge[cnt].u=u;
  edge[cnt].v=v;
  edge[cnt].w=w;
  edge[cnt].next=head[u];
  head[u]=cnt++;
}
bool spfa(){
  queue<int> q;
  dis[1]=0;
  q.push(1);
  color[1]++;
  while(!q.empty()){
    int u=q.front();
    q.pop();
    for(int i=head[u];~i;i=edge[i].next){
      if(dis[edge[i].v]>dis[u]+edge[i].w){
        dis[edge[i].v]=dis[u]+edge[i].w;
        q.push(edge[i].v);
        if(++color[edge[i].v]>=n) return false;
      }
    }
  }
  return true;
}
int main(){
  int T;
  int q,u,v,w;
  scanf("%d", &T);
  for(int s=1;s<=T;s++){
    init();
    scanf("%d", &n);
    for(int i=1;i<=n;i++){
      scanf("%d", &d[i]);
    }
    scanf("%d", &t);
    for(int i=0;i<t;i++){
      scanf("%d %d", &u, &v);
      add(u,v,(d[v]-d[u])*(d[v]-d[u])*(d[v]-d[u]));
    }
    bool ll=spfa();
    scanf("%d", &q);
    printf("Case %d:\n", s);
    while(q--){
      scanf("%d", &w);
      int ans=dis[w];
      if(ans<3||ans==INF) printf("?\n");
      else printf("%d\n", dis[w]);
    }
  }
  return 0;
}

/*
Frogger
POJ - 2253
https://cn.vjudge.net/problem/POJ-2253#author=541607120101
题意:求一条1~2的路径 使得路径上的最大边权最小.
输入:石头数量 x y
样例输入:
      2
      0 0
      3 4
      3
      17 4
      19 4
      18 5
      0
样例输出:
      Scenario #1
      Frog Distance = 5.000

      Scenario #2
      Frog Distance = 1.414
思路:
dijkstra 计算边权最小即可
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <cmath>a
#define maxn 1005
#define INF 0x3f3f3f
using namespace std;
struct node{
  int x,y;
}num[maxn];
double mp[maxn][maxn];
double calc(int i, int j) {
    return (sqrt(pow((double)num[i].x-num[j].x, 2)+pow((double)num[i].y-num[j].y, 2)));
}
int n;
double dijkstra() {
    bool vis[maxn];
    double d[maxn];
    memset(vis, false, sizeof(vis));
    for(int i=0; i<n; i++) {
        d[i] = mp[0][i];
    }
    d[0] = 0;
    vis[0] = true;
    for(int i=0; i<n-1; i++) {
        double m = INF; int x;
        for(int y=0; y<n; y++) if(!vis[y] && m >= d[y]) m = d[x=y];
        vis[x] = true;
        for(int y=0; y<n; y++){
            if(!vis[y]) {
                double maxx = max(d[x], mp[x][y]);
                if(d[y] > maxx) d[y] = maxx;
            }
        }
    }
    return d[1];
}
int main(){
  int m=0;
  while(cin>>n,n){
    m++;
    for(int i=0;i<n;i++) cin>>num[i].x>>num[i].y;
    for(int i=0;i<n;i++){
      for(int j=0;j<n;j++){
        mp[i][j]=mp[j][i]=calc(i,j);
      }
      mp[i][i]=0;
    }
    printf("Scenario #%d\n", m);
    printf("Frog Distance = %.3lf\n\n", dijkstra());
  }
  return 0;
}

/*
Heavy Transportation
POJ - 1797
https://cn.vjudge.net/problem/POJ-1797
题面 找出从1到n的路,使其称重最大
输入:T组样例 点个数和边个数
      u -> v  w
样例输入:
      1
      3 3
      1 2 3
      1 3 4
      2 3 5
样例输出:
      Scenario #1:
思路:
dijkstra 
*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
int w[1010][1010];
int d[1010];
bool vis[1010];
int n,m;
void djs()
{
    for(int i=1; i<=n; i++)
    {
        d[i]=w[1][i];
        vis[i]=0;
    }
    for(int i=1; i<=n; i++)
    {
        int m=-1;
        int x=-1;
        for(int j=1; j<=n; j++)
            if(!vis[j]&&d[j]>m)
                m=d[x=j];
        if(x!=-1)
        {
            vis[x]=1;
            for(int j=1; j<=n; j++)
                if(!vis[j]&&d[j]<min(d[x],w[x][j]))
                    d[j]=min(d[x],w[x][j]);//维护d数组
        }
    }
}
int main()
{
    int T,t=1;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)
                w[i][j]=i==j?0:-1;
        for(int i=1; i<=m; i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            if(w[x][y]<z)
                w[x][y]=w[y][x]=z;
        }
        djs();
        printf("Scenario #%d:\n%d\n\n",t++,d[n]);
    }
}

/*
Invitation Cards
POJ - 1511
https://cn.vjudge.net/problem/POJ-1511#author=ty21
题意: 求最短路
输入: 点 边
      u->v w
样例输入:
      2
      2 2
      1 2 13
      2 1 33
      4 6
      1 2 10
      2 1 60
      1 3 20
      3 4 10
      2 4 5
      4 1 50
样例输出:
      46
      210
思路:
双向SPFA
*/
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
#define maxn 1000100
#define INF 0x3f3f3f
struct node{
  int u,v;
  int w;
  int next;
}edge[maxn],uedge[maxn];
int head[maxn],uhead[maxn];
int dis[maxn],udis[maxn];
int cnt,ucnt,n,t;
void init(){
  memset(head,-1,sizeof head);
  memset(uhead,-1,sizeof uhead);
  memset(dis,INF,sizeof dis);
  memset(udis,INF, sizeof udis);
  cnt=0;
  ucnt=0;
}
void add(int u,int v,int w,int &cnt, int *head, node *edge){
  edge[cnt].w=w;
  edge[cnt].u=u;
  edge[cnt].v=v;
  edge[cnt].next=head[u];
  head[u]=cnt++;
}
void spfa(int st,int *dis,int *head, node *edge){
  dis[st]=0;
  queue<int> q;
  q.push(st);
  while(!q.empty()){
    int u=q.front();
    q.pop();
    for(int i=head[u];~i;i=edge[i].next){
      if(dis[edge[i].v]>dis[u]+edge[i].w){
        dis[edge[i].v]=dis[u]+edge[i].w;
        q.push(edge[i].v);
      }
    }
  }
}
int main(){
  int T,u,v,w;
  scanf("%d", &T);
  while(T--){
    init();
    scanf("%d %d", &n, &t);
    for(int i=0;i<t;i++){
      scanf("%d %d %d", &u, &v, &w);
      add(u,v,w,cnt,head,edge);
      add(v,u,w,ucnt,uhead,uedge);
    }
    spfa(1,dis,head,edge);
    spfa(1,udis,uhead,uedge);
    long long ans=0;
    for(int i=1;i<=n;i++){
      ans+=(long long)(udis[i]+dis[i]);
    }
    printf("%lld\n", ans);
  }
  return 0;
}

/*
Layout
POJ - 3169
https://cn.vjudge.net/problem/POJ-3169
题意:关系好的奶牛想在一起,关系不好的奶牛想远离对方,问1的n的距离
输入:奶牛数 关系好的个数t1 关系不好的个数t2
      t1行 a b 之间最多 d
      t2行 a b 之间最少 d
样例输入:
      4 2 1
      1 3 10
      2 4 20
      2 3 3
样例输出:
      27
解法:
差分约束
关系好: dis[b]-dis[a]<d a<b add(a,b,d)
关系坏: dis[a]-dis[b]<d a>b add(a,b,d)
*/
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <iostream>
#include <cmath>
using namespace std;
#define maxn 1000000
#define INF 0x3f3f3f3f
struct node{
  int u,v,w;
  int next;
}edge[maxn];
int head[maxn];
int dis[maxn];
int color[maxn];
int cnt,n,t1,t2;
void init(){
  memset(head,-1,sizeof head);
  memset(dis,INF,sizeof dis);
  memset(color,0,sizeof color);
  cnt=0;
}
void add(int u,int v,int w){
  edge[cnt].u=u;
  edge[cnt].v=v;
  edge[cnt].w=w;
  edge[cnt].next=head[u];
  head[u]=cnt++;
}
bool spfa(){
  queue<int> q;
  dis[1]=0;
  q.push(1);
  color[1]++;
  while(!q.empty()){
    int u=q.front();
    q.pop();
    for(int i=head[u];~i;i=edge[i].next){
      if(dis[edge[i].v]>dis[u]+edge[i].w){
        dis[edge[i].v]=dis[u]+edge[i].w;
        q.push(edge[i].v);
        if(++color[edge[i].v]>=n) return false;
      }
    }
  }
  return true;
}
int main(){
  scanf("%d %d %d", &n, &t1, &t2);
  init();
  int u,v,w;
  for(int i=0;i<t1;i++){
    scanf("%d %d %d", &u, &v, &w);
    if(u>v)swap(u,v);
    add(u,v,w);
  }
  for(int i=0;i<t2;i++){
    scanf("%d %d %d", &u, &v, &w);
    if(u<v)swap(u,v);
    add(u,v,-w);
  }
  if(spfa()){
    if(dis[n]==INF){
      printf("-2\n");
    }else{
      printf("%d\n", dis[n]);
    }
  }else{
    printf("-1\n");
  }
  return 0;
}

/*
Marriage Match IV
HDU - 3416
https://cn.vjudge.net/problem/HDU-3416
题意:  找出所有最短路的个数
输入 :
      T组样例
      点 边
      u->v w
      B E
样例输入:
      2
      7 8
      1 2 1
      1 3 1
      2 4 1
      3 4 1
      4 5 1
      4 6 1
      5 7 1
      6 7 1
      1 7

      2 2
      1 2 1
      1 2 2
      1 2
样例输出:
      2
      1
解法:
双向SPFA枚举每条边找出最短路的连通图
最大流求最短路的个数
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<iostream>
using namespace std;
#define INF 0x3f3f3f
#define maxn 100010
struct node{
  int u, v, w;
  int next;
}edge[maxn], uedge[maxn], wedge[maxn*2];
int head[maxn], uhead[maxn], whead[maxn];
int cnt, ucnt, wcnt;
int dis[maxn], udis[maxn];
int d[maxn];
int t,n,B,E;
void init(){
  memset(head, -1, sizeof head);
  memset(uhead, -1, sizeof uhead);
  memset(whead, -1, sizeof whead);
  memset(dis, INF, sizeof dis);
  memset(udis, INF, sizeof udis);
  cnt = ucnt = wcnt = 0;
}
void add(int u, int v, int w, node edge[], int  &cnt, int *head){
  edge[cnt].w=w;
  edge[cnt].u=u;
  edge[cnt].v=v;
  edge[cnt].next=head[u];
  head[u]=cnt++;
}
void add_dinic(int u,int v,int w){
  wedge[wcnt].w=w;
  wedge[wcnt].u=u;
  wedge[wcnt].v=v;
  wedge[wcnt].next=whead[u];
  whead[u]=wcnt++;

  wedge[wcnt].w=0;
  wedge[wcnt].u=v;
  wedge[wcnt].v=u;
  wedge[wcnt].next=whead[v];
  whead[v]=wcnt++;
}
void spfa(int st, int *dis, int *head, node edge[]){
  queue<int> q;
  bool color[maxn];
  memset(color,true,sizeof color);
  q.push(st);
  dis[st]=0;
  color[st]=false;
  while(!q.empty()){
    int u=q.front();
    q.pop();
    color[u]=true;
    for(int i=head[u];~i;i=edge[i].next){
      if(dis[u]+edge[i].w<dis[edge[i].v]){
        dis[edge[i].v]=dis[u]+edge[i].w;
        if(color[edge[i].v]){
            q.push(edge[i].v);
            color[edge[i].v]=false;
        }
      }
    }
  }
}
bool bfs(int B,int E){
  memset(d,-1,sizeof d);
  queue<int> q;
  d[B]=0;
  q.push(B);
  while(!q.empty()){
    int st=q.front();
    q.pop();
    for(int i=whead[st];~i;i=wedge[i].next){
      if(d[wedge[i].v]==-1&&wedge[i].w>0){
        d[wedge[i].v]=d[st]+1;
        q.push(wedge[i].v);
      }
    }
  }
  return d[E]!=-1;
}
int dfs(int a,int b){
  int r=0;
  if(a==E) return b;
  for(int i=whead[a];~i;i=wedge[i].next){
    if(wedge[i].w>0&&d[wedge[i].v]==d[a]+1){
      int x=min(wedge[i].w,b-r);
      x=dfs(wedge[i].v,x);
      r+=x;
      wedge[i].w-=x;
      wedge[i^1].w+=x;
    }
  }
  if(!r) d[a]=-2;
  return r;
}
int dinic(int B,int E){
  int ans=0;
  int t;
  while(bfs(B,E)){
    while(t=dfs(B,INF)) ans+=t;
  }
  return ans;
}
int main(){
  int T;
  scanf("%d", &T);
  while(T--){
    scanf("%d %d", &n, &t);
    init();
    for(int i=0;i<t;i++){
      int u,v,w;
      scanf("%d %d %d", &u, &v, &w);
      add(u, v, w, edge, cnt, head);
      add(v, u, w, uedge, ucnt, uhead);
    }
    scanf("%d %d", &B ,&E);
    spfa(B, dis, head, edge);
    if(dis[E]==INF){
      printf("0\n");
      continue;
    }
    long long tmp = dis[E];
    spfa(E, udis, uhead, uedge);
    for(int i=0;i<t;i++){
      int u=edge[i].u,v=edge[i].v;
      if(edge[i].w&&dis[u]+udis[v]+edge[i].w==tmp){
        add_dinic(u,v,1);
      }
    }
    printf("%d\n", dinic(B,E));
  }
  return 0;
}

/*
MPI Maelstrom
POJ - 1502
https://cn.vjudge.net/problem/POJ-1502#author=weissice
题意:
      求从一台电脑发出的消息到最后一台电脑收到的最短时间
输入:
      n台计算机
      以矩阵形式输出相邻电脑通讯需要的时间,只有矩阵的下三角
样例输入:
      5
      50
      30 5
      100 20 50
      10 x x 10
样例输出:
      35
注意:
stoi()不是标准库里面的函数,会 Compile Error
*/
#include <cstring>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
#define INF 0x3f3f3f
#define maxn 110
int mp[maxn][maxn];
int dis[maxn];
int n,B=1;
int return_int(char *a){
  int ans=0;
  int len=strlen(a);
  for(int i=0;i<len;i++){
    ans=a[i]-'0'+ans*10;
  }
  return ans;
}
void init(){
  memset(mp,INF,sizeof mp);
  memset(dis,INF,sizeof dis);
}
void spfa(int B){
  dis[B]=0;
  queue<int> q;
  q.push(B);
  while(!q.empty()){
    int u=q.front();
    q.pop();
    for(int i=1;i<=n;i++){
      if(dis[i]>dis[u]+mp[u][i]){
        dis[i]=dis[u]+mp[u][i];
        q.push(i);
      }
    }
  }
  return ;
}
int main(){
  scanf("%d", &n);
  init();
  char a[10];
  for(int i=1;i<=n;i++){
    for(int j=1;j<i;j++){
      scanf("%s", a);
      if(a[0]!='x') mp[i][j]=mp[j][i]=return_int(a);
    }
  }
  spfa(B);
  int ans=0;
  for(int i=1;i<=n;i++){
    if(ans<dis[i]) ans=dis[i];
  }
  printf("%d\n", ans);
  return 0;
}

/*
Silver Cow Party
POJ - 3268
https://cn.vjudge.net/problem/POJ-3268#author=chenchonghan
题意:n个点m条边牛全要到x参加聚会然后在回家,问任意一台奶牛行走的最长时间
输入: 点 边 聚会地点
      u -> v  w
样例输入:
      4 8 2
      1 2 4
      1 3 2
      1 4 7
      2 1 1
      2 3 5
      3 1 2
      3 4 4
      4 2 3
样例输出:
      10
直接跑两边spfa即可
*/
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
#define maxn 1000100
#define INF 0x3f3f3f
struct node{
  int u,v;
  int w;
  int next;
}edge[maxn],uedge[maxn];
int head[maxn],uhead[maxn];
int dis[maxn],udis[maxn];
int cnt,ucnt,n,t,st;
void init(){
  memset(head,-1,sizeof head);
  memset(uhead,-1,sizeof uhead);
  memset(dis,INF,sizeof dis);
  memset(udis,INF, sizeof udis);
  cnt=0;
  ucnt=0;
}
void add(int u,int v,int w,int &cnt, int *head, node *edge){
  edge[cnt].w=w;
  edge[cnt].u=u;
  edge[cnt].v=v;
  edge[cnt].next=head[u];
  head[u]=cnt++;
}
void spfa(int st,int *dis,int *head, node *edge){
  dis[st]=0;
  queue<int> q;
  q.push(st);
  while(!q.empty()){
    int u=q.front();
    q.pop();
    for(int i=head[u];~i;i=edge[i].next){
      if(dis[edge[i].v]>dis[u]+edge[i].w){
        dis[edge[i].v]=dis[u]+edge[i].w;
        q.push(edge[i].v);
      }
    }
  }
}
int main(){
    scanf("%d %d %d", &n, &t, &st);
    int u,v,w;
    init();
    for(int i=0;i<t;i++){
      scanf("%d %d %d", &u, &v, &w);
      add(u,v,w,cnt,head,edge);
      add(v,u,w,ucnt,uhead,uedge);
    }
    spfa(st,dis,head,edge);
    spfa(st,udis,uhead,uedge);
    int ans=0;
    for(int i=1;i<=n;i++){
      ans=max(ans,udis[i]+dis[i]);
    }
    printf("%d\n", ans);
  return 0;
}

/*
Subway
POJ - 2502
https://cn.vjudge.net/problem/POJ-2502#author=0
题面: 从家到学校,可以选择坐(40km/s)地铁或(10km/s)步行,求最短时间
输入  第一行 起点坐标,终点坐标
      下面是每个地铁经过的站 知道-1 -1结束
样例输入:
      0 0 10000 1000
      0 200 5000 200 7000 200 -1 -1
      2000 600 5000 600 10000 600 -1 -1
样例输出:
      21
解法:
      建图,跑一遍Floyed-Warshall
*/
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <queue>
#include <cmath>
using namespace std;
#define maxn 1000
#define INF 0x3f3f3f
struct node{
  double x,y;
  int kid;
}poi[maxn];
double mp[maxn][maxn];
int cnt=0;
void build(double x,double y,int kid){
  poi[cnt].x=x;
  poi[cnt].y=y;
  poi[cnt].kid=kid;
  cnt++;
}
int main(){
  double x,y;
  int kid=0;
  scanf("%lf %lf", &x, &y);
  build(x,y,kid++);
  scanf("%lf %lf", &x, &y);
  build(x,y,kid++);
  while(~scanf("%lf %lf", &x, &y)) {
    if(x<0&&y<0){
      kid++;
      continue;
    }
    build(x,y,kid);
  }
  for(int i=0;i<cnt;i++){
    for(int j=0;j<cnt;j++){
      mp[i][j]=sqrt((poi[i].x-poi[j].x)*(poi[i].x-poi[j].x)+(poi[i].y-poi[j].y)*(poi[i].y-poi[j].y))/(10000.0/60);
    }
  }
  for(int i=0;i<cnt-1;i++){
    if(poi[i].kid==poi[i+1].kid){
      mp[i][i+1]=mp[i+1][i]=sqrt((poi[i].x-poi[i+1].x)*(poi[i].x-poi[i+1].x)+(poi[i].y-poi[i+1].y)*(poi[i].y-poi[i+1].y))/(40000.0/60);
    }
  }
  for(int k=0;k<cnt;k++){
    for(int i=0;i<cnt;i++){
      for(int j=0;j<cnt;j++){
        mp[i][j]=min(mp[i][k]+mp[k][j],mp[i][j]);
      }
    }
  }
  printf("%d\n", (int)(mp[0][1]+0.5));
  return 0;
}

/*
The Shortest Path in Nya Graph
HDU - 4725
https://cn.vjudge.net/problem/HDU-4725#author=0
题意:求从1到n的最短路,有层数,点可能不在同一层
输入:节点数 额外边数 相邻层移动的成本
样例输入:
      2
      3 3 3
      1 3 2
      1 2 1
      2 3 1
      1 3 3

      3 3 3
      1 3 2
      1 2 2
      2 3 2
      1 3 4
样例输出:
      Case #1: 2
      Case #2: 3
解法:
点与点建边,层与层建边,然后层上的点与相邻层和本层建边
spfa
*/
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <iostream>
#include <cmath>
using namespace std;
#define maxn 1000000
#define INF 0x3f3f3f3f
struct node{
  int u,v,w;
  int next;
}edge[maxn*3];
int head[maxn];
int dis[maxn];
int vv[maxn], lay[maxn];
int cnt,n,t,c;
void init(){
  memset(head,-1,sizeof head);
    memset(vv,0,sizeof(vv));
  memset(dis,INF,sizeof dis);
  cnt=0;
}
void add(int u,int v,int w){
  edge[cnt].u=u;
  edge[cnt].v=v;
  edge[cnt].w=w;
  edge[cnt].next=head[u];
  head[u]=cnt++;
}
void spfa(){
  queue<int> q;
  dis[1]=0;
  q.push(1);
  while(!q.empty()){
    int u=q.front();
    q.pop();
    for(int i=head[u];~i;i=edge[i].next){
      if(dis[edge[i].v]>dis[u]+edge[i].w){
        dis[edge[i].v]=dis[u]+edge[i].w;
        q.push(edge[i].v);
      }
    }
  }
  return ;
}
int main(){
  int T;
  int q,u,v,w;
  scanf("%d", &T);
  for(int s=1;s<=T;s++){
    scanf("%d %d %d", &n, &t, &c);
    init();
    for(int i=1;i<=n;i++){
        scanf("%d", &q);
        lay[i]=q;
        vv[q]=1;
    }
    for(int i = 1; i < n; i++){
        if(vv[i]&&vv[i+1]){
            add(n+i,n+i+1,c);
            add(n+i+1,n+i,c);
        }
    }
    for(int i = 1; i <= n; i++) {
        add(n+lay[i],i,0);
        if(lay[i] > 1)
            add(i,n+lay[i]-1,c);
        if(lay[i] < n)
            add(i,n+lay[i]+1,c);
    }
    for(int i=0;i<t;i++){
      scanf("%d %d %d", &u, &v, &w);
      add(u,v,w);
      add(v,u,w);
    }
    spfa();
    if(dis[n]==INF) dis[n]=-1;
    printf("Case #%d: %d\n", s, dis[n]);
  }
  return 0;
}

/*
Til the Cows Come Home
POJ - 2387
https://cn.vjudge.net/problem/POJ-2387
题意:最短路裸题
输入:点 边
      u -> v w
样例输入:
      5 5
      1 2 20
      2 3 30
      3 4 20
      4 5 20
      1 5 100
样例输出:
      90
解法:
      SPFA
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<iostream>
using namespace std;
#define INF 0x3f3f3f
#define maxn 10010
struct node{
  int u;
  int v;
  int w;
  int next;
}edge[maxn],uedge[maxn];
int cnt,ucnt;
int t,n;
int head[maxn],uhead[maxn];
int dis[maxn], udis[maxn];
void init(){
  memset(head,0,sizeof head);
  memset(dis,INF,sizeof dis);
  cnt=1;
}
void add(int u, int v, int w, node edge[], int &cnt,int *head){
  edge[cnt].w=w;
  edge[cnt].u=u;
  edge[cnt].v=v;
  edge[cnt].next=head[u];
  head[u]=cnt++;
}
void spfa(int st,int dis[],int head[],node edge[]) {
	dis[st] = 0;
	queue<int>q;
	q.push(st);
	while (!q.empty()) {
		int u = q.front();
		q.pop();
		for (int i = head[u]; i!=0; 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(v);
			}
		}
	}
	return;
}
int main(){
  while(~scanf("%d %d", &t, &n)){
    init();
    int u,v,w;
    for(int i=0;i<t;i++){
      scanf("%d %d %d", &u, &v, &w);
      add(u, v, w, edge, cnt, head);
      add(v, u, w, edge, cnt, head);
      //add(v, u, w, uedge, ucnt, uhead);
    }
    spfa(1, dis, head, edge);
    cout<<dis[n]<<endl;
  }
  return 0;
}

/*
Tram
POJ - 1847
https://cn.vjudge.net/problem/POJ-1847
题意:从A到B要选择开关的次数,开关默认指向第一个交叉点
输入:N个交叉点数,从A到B
      第i行第一个数表示第i个交叉节点可以连其他节点的个数,Ki表示连接的节点
样例输入:
      3 2 1
      2 2 3
      2 3 1
      2 1 2
样例输出:
      0
解法
建图,直接跑Floyed——warshall
*/
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#define maxn 110
#define INF 0x3f3f3f3f
int mp[maxn][maxn];
int N,A,B;
int main(){
  while(~ scanf("%d %d %d", &N, &A, &B)){
    memset(mp,INF,sizeof mp);
    for(int i=1;i<=N;i++){
      int n,m;
      scanf("%d", &n);
      if(n==0) continue;
      scanf("%d", &m);
      mp[i][m]=0;
      n--;
      while(n--){
        scanf("%d", &m);
        mp[i][m]=min(1,mp[i][m]);
        mp[m][i]=min(1,mp[m][i]);
      }
    }
    for(int k=1;k<=N;k++){
      for(int i=1;i<=N;i++){
        for(int j=1;j<=N;j++){
          if(mp[i][j]>mp[i][k]+mp[k][j])
            mp[i][j]=mp[i][k]+mp[k][j];
        }
      }
    }
    if(mp[A][B] == INF) printf("-1\n");
    else printf("%d\n", mp[A][B]);
  }
  return 0;
}

/*
Wormholes
POJ - 3259
https://cn.vjudge.net/problem/POJ-3259#author=SCU2018
题意: 通过虫洞回到这个原点之前的时间
      虫洞路径分为两种,双向的时间是正方向,单向的时间是反方向
输入:
      T组样例
      点,双向路径, 单向路径
      u v w
样例输入:
      2
      3 3 1
      1 2 2
      1 3 4
      2 3 1
      3 1 3

      3 2 1
      1 2 3
      2 3 4
      3 1 8
样例输出:
      NO
      YES
思路:
SPFA直接跑,要是发现原点时间减小了,就输出YES否NO
*/
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
using namespace std;
#define maxn  100010
#define INF 0x3f3f3f
struct node{
  int u,v,w;
  int next;
}edge[maxn];
int head[maxn];
int dis[maxn];
int n,m1,m2;
int cnt,B=1,E=n;
void init(){
  memset(head,-1,sizeof head);
  memset(dis,INF,sizeof dis);
  cnt=0;
}
void add(int u,int v,int w){
    edge[cnt].u=u;
    edge[cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
bool spfa(int B){
  dis[B]=0;
  queue<int> q;
  q.push(B);
  while(!q.empty()){
    int u=q.front();
    q.pop();
    for(int i=head[u];~i;i=edge[i].next){
      if(dis[edge[i].v]>dis[u]+edge[i].w){
        dis[edge[i].v]=dis[u]+edge[i].w;
        if(dis[B]<0) return true;
        q.push(edge[i].v);
      }
    }
  }
  return false;
}
int main(){
  int T;
  scanf("%d", &T);
  while(T--){
    scanf("%d %d %d", &n, &m1, &m2);
    init();
    int u,v,w;
    for(int i=0;i<m1;i++){
      scanf("%d %d %d", &u, &v, &w);
      add(u,v,w);
      add(v,u,w);
    }
    for(int i=0;i<m2;i++){
      scanf("%d %d %d", &u, &v, &w);
      add(u,v,-w);
    }
    if(spfa(B)) printf("YES\n");
    else printf("NO\n");
  }
  return 0;
}

/*
昂贵的聘礼
POJ - 1062
https://cn.vjudge.net/problem/POJ-1062
题意:他和酋长买东西,他可以通过和别人交换来找减少自己最少要花费的金币,但只能在等级差内交易
输入  等级差距 N个物品的总数
      物品价格 主人地位 代替品总数
      代替品的编号,优惠价格
样例输入:
      1 4
      10000 3 2
      2 8000
      3 5000
      1000 2 1
      4 200
      3000 2 1
      4 200
      50 2 0
样例输出:
      5250
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
#define maxn 100000
#define INF 0x3f3f3f
struct node{
  int u,v,w;
  int next;
}edge[maxn];
int head[maxn];
int dis[maxn];
int cnt,m,n;
bool color[maxn];
int l[maxn];
void init(){
  memset(head,-1,sizeof head);
  memset(dis,INF,sizeof dis);
  memset(color,true,sizeof color);
  cnt=0;
}
void add(int u,int v,int w){
  edge[cnt].u=u;
  edge[cnt].v=v;
  edge[cnt].w=w;
  edge[cnt].next=head[u];
  head[u]=cnt++;
}
void spfa(){
  queue<int> q;
  q.push(0);
  dis[0]=0;
  while(!q.empty()){
    int st=q.front();
    q.pop();
    for(int i=head[st];~i;i=edge[i].next){
      if(dis[st]+edge[i].w<dis[edge[i].v]&&color[edge[i].v]){
        dis[edge[i].v]=dis[st]+edge[i].w;
        q.push(edge[i].v);
      }
    }
  }
}
int solve(){
  int ans=INF;
  for(int i=1;i<=n;i++){
    memset(dis,INF,sizeof dis);
    memset(color,true,sizeof color);
    int minle=l[i];
    for(int j=1;j<=n;j++){
      if(l[j]<minle||l[j]-minle>m){
          color[j]=false;
      }
    }
    spfa();
    ans=min(ans,dis[1]);
  }
  return ans;
}
int main(){
  init();
  scanf("%d %d", &m, &n);
  int p,x;
  int t,v;
  for(int i=1;i<=n;i++){
    scanf("%d %d %d", &p, &l[i], &x);
    add(0,i,p);
    while(x--){
      scanf("%d %d",&t, &v);
      add(t,i,v);
    }
  }
  printf("%d\n", solve());
  return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值