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

小结:

1,求1到其他点的最短路,和其他点到1的最短路,只需要反边即可。

2. 最短路维护边可以加,有时乘也是更新可以最短路的。

3,spfa判负圈只需要判断一个点入队次数>n,那么必有负圈。

4.如果对最短路更新进行了限制,那么不要直接更新,打上标记之后更新。

5.最短路可以抽象为01规划,每个边可以取,可以不取。

6.传递闭包往往会很像拓扑。

7.必要时把边权压成点权,边和边之间可能也会有权。

A - Til the Cows Come Home

 POJ - 2387 

板题:

#include<cstdio>
#include<vector>
#include<queue>
using namespace std;
#define pb push_back
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=1e3+5;
int n,m;
struct edge{int v,w;edge(int a,int b){v=a,w=b;}};
struct node{
    int id,dis;
    node(int a,int b){id=a,dis=b;}
    friend bool operator<(node a,node b){
    return a.dis>b.dis;
    }
};
vector<edge>e[maxn];
int dis[maxn];
bool done[maxn];
void dijkstra(){
    int s=1;
    for(int i=0;i<=n;i++)dis[i]=inf,done[i]=0;
    dis[s]=0;
    priority_queue<node>Q;
    Q.push(node(s,0));
    while(!Q.empty()){
    node u=Q.top();Q.pop();
    if(done[u.id])continue;
    done[u.id]=1;
    for(int i=0;i<e[u.id].size();i++){
    edge y=e[u.id][i];
    if(done[y.v])continue;
    if(dis[y.v]>y.w+dis[u.id]){
    dis[y.v]=y.w+u.dis;
    Q.push(node(y.v,dis[y.v]));
    }
    }
    }
}
int main(){
    int t;
    scanf("%d %d",&t,&n);
    for(int i=1,u,v,w;i<=t;i++){
    scanf("%d %d %d",&u,&v,&w);
    e[u].pb(edge(v,w));
    e[v].pb(edge(u,w));
    }
    dijkstra();
    printf("%d
",dis[n]);
    // system("pause");
    return 0;
}
View Code

B - Frogger

 POJ - 2253 

无法优化,构建图的复杂度都是O(N*N)的,上floyd

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define rep(i,j,k) for(int i=(int)j;i<=(int)k;i++)
#define per(i,j,k) for(int i=(int)k;i>=(int)j;i--)
#define pb push_back
typedef double db;
const int maxn=2e2+5;
struct point{db x,y;}P[maxn];
db dis(point a,point b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}
db gp[maxn][maxn];
int main(){
    int n,cas=0;
    while(~scanf("%d",&n),n){
    for(int i=1;i<=n;i++)scanf("%lf %lf",&P[i].x,&P[i].y);
    // db ans=dis(P[1],P[2]);
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    gp[i][j]=dis(P[i],P[j]);
    for(int k=1;k<=n;k++)
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    gp[i][j]=min(gp[i][j],max(gp[i][k],gp[k][j]));
    db ans=gp[1][2];
    printf("Scenario #%d
",++cas);
    printf("Frog Distance = %.3lf

",ans);
    }
    // system("pause");
    return 0;
}
View Code

C - Heavy Transportation

 POJ - 1797 

就是说1到n有多条路,每一条路权值必然由最小边决定,问你那条路权值最大。

两种做法:

1.最大生成树:
将边按照由大到小排序,不断加边,如果突然加入一条边1,到n联通了,说明这个就是答案。

这样保证了路径的权值由最小值决定,而且保证了最小值最大化。因为其他连边必然比当前ans小。

 1 #include<cstdio>
 2 #include<vector>
 3 #include<queue>
 4 #include<algorithm>
 5 using namespace std;
 6 #define pb push_back
 7 typedef long long ll;
 8 const int inf=0x3f3f3f3f;
 9 const int maxn=1e3+5;
10 int n,m;
11 int fa[maxn];
12 struct edge{int u,v,w;edge(int a,int b,int x){u=a,v=b,w=x;}};
13 vector<edge>e;
14 bool cmp(edge a,edge b){return a.w>b.w;}
15 void init(){for(int i=1;i<=maxn;i++)fa[i]=i;}
16 int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
17 void build(int x,int y){int dx=find(x),dy=find(y);if(dx!=dy)fa[dx]=dy;}
18 int main(){
19     int t,cas=0;
20     scanf("%d",&t);
21     while(t--){
22     e.clear();
23     scanf("%d %d",&n,&m);
24     for(int i=1;i<=n;i++)fa[i]=i;
25     for(int i=1,u,v,w;i<=m;i++){
26     scanf("%d %d %d",&u,&v,&w);
27     e.pb(edge(u,v,w));
28     }
29     sort(e.begin(),e.end(),cmp);
30     int ans=0;
31     for(int i=0;i<e.size();i++){
32     build(e[i].v,e[i].u);
33     if(find(1)==find(n)){ans=e[i].w;break;}
34     }
35     printf("Scenario #%d:
",++cas);
36     printf("%d

",ans);
37     }
38     // system("pause");
39     return 0;
40 }
View Code

2.最短路维护:
dis不再表示最短路,而表示某个点到源点路径的权值。

那么必然有:dis[v]<min(dis[u],w) 的更新条件,求最大权值,初始化为0而非inf,不断更新路径上的最小边,使其最大。

 1 #include<cstdio>
 2 #include<vector>
 3 #include<queue>
 4 #include<algorithm>
 5 using namespace std;
 6 #define pb push_back
 7 typedef long long ll;
 8 const int inf=0x3f3f3f3f;
 9 const int N=1e5+5;
10 struct edge{int v,w;edge(int a,int b){v=a,w=b;}};
11 vector<edge>e[N];
12 int n,m;
13 int dis[N];
14 bool inq[N];
15 void spfa(int s){
16     for(int i=1;i<=n;i++)dis[i]=0,inq[i]=0;
17     dis[s]=inf;
18     queue<int>Q;
19     Q.push(s);inq[s]=1;
20     while(!Q.empty()){
21     int u=Q.front();Q.pop();inq[u]=0;
22     for(int i=0;i<e[u].size();i++){
23         int v=e[u][i].v,w=e[u][i].w;
24     if(dis[v]<min(dis[u],w)){
25     dis[v]=min(dis[u],w);
26     if(!inq[v])Q.push(v),inq[v]=1;
27     }
28     }
29     }
30 }
31 int main(){
32     int t,cas=0;
33     scanf("%d",&t);
34     while(t--){
35     scanf("%d %d",&n,&m);
36     for(int i=1;i<=n;i++)e[i].clear();
37     for(int i=1,u,v,w;i<=m;i++){
38     scanf("%d %d %d",&u,&v,&w);
39     e[u].pb(edge(v,w));
40     e[v].pb(edge(u,w));
41     }
42     spfa(1);
43     printf("Scenario #%d:
",++cas);
44     printf("%d

",dis[n]);
45     }
46     // system("pause");
47     return 0;
48 }
View Code

D - Silver Cow Party

 POJ - 3268 

无脑题;

#include<cstdio>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
#define pb push_back
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=1e5+5;
struct edge{int v,w;edge(int a,int b){v=a,w=b;}};
vector<edge>e[N];
int n,m;
int dis[N];
bool inq[N];
void spfa(int s){
    for(int i=1;i<=n;i++)dis[i]=inf,inq[i]=0;
    dis[s]=0;
    queue<int>Q;
    Q.push(s);inq[s]=1;
    while(!Q.empty()){
    int u=Q.front();Q.pop();inq[u]=0;
    for(int i=0;i<e[u].size();i++){
        int v=e[u][i].v,w=e[u][i].w;
    if(dis[v]>dis[u]+w){
    dis[v]=dis[u]+w;
    if(!inq[v])Q.push(v),inq[v]=1;
    }
    }
    }
}
int a[N];
int main(){
    int x;
    scanf("%d %d %d",&n,&m,&x);
    // for(int i=1;i<=n;i++)e[i].clear();
    for(int i=1,u,v,w;i<=m;i++){
    scanf("%d %d %d",&u,&v,&w);
    e[u].pb(edge(v,w));
    }
    spfa(x);
    for(int i=1;i<=n;i++)a[i]=dis[i];
    for(int i=1;i<=n;i++)        
    if(i!=x)spfa(i),a[i]+=dis[x];
    int ans=*max_element(a+1,a+1+n);
    printf("%d
",ans);
    // }
    // system("pause");
    return 0;
}
View Code

E - Currency Exchange

 POJ - 1860 

就是说n种货币,可以相互交换,问你能不能交换过程中把钱变多。

如果钱变多,说明有正圈,陷在正圈里不出来,肯定一直变多。直接判正圈。

如果说一个点入队次数大于n,说明有正圈。

注意蛋疼的精度,eps设大了不行。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<map>
 4 #include<vector>
 5 #include<string>
 6 #include<cstring>
 7 #include<queue>
 8 using namespace std;
 9 #define pb push_back
10 const int inf=0x3f3f3f3f;
11 struct edge{int v;double r,c;edge(int x,double y,double z){v=x,r=y,c=z;}};
12 const int N=1e2+5;  
13 const double eps=1e-10;
14 vector<edge>e[N];
15 int n,m,s;
16 double V;
17 bool flag;
18 bool inq[N];int cnt[N];
19 double dis[N];
20 void spfa(){
21     for(int i=1;i<=n;i++)cnt[i]=0,inq[i]=0,dis[i]=0.0;
22     queue<int>Q;
23     Q.push(s);inq[s]=1;dis[s]=V;
24     while(!Q.empty()){
25         int u=Q.front();Q.pop();inq[u]=0;
26         for(int i=0;i<e[u].size();i++){
27             int v=e[u][i].v;double r=e[u][i].r,c=e[u][i].c;
28             double val=(dis[u]-c)*r;
29             if(dis[v]<val){
30                 dis[v]=val;
31                 if(inq[v])continue;
32                 Q.push(v),inq[v]=1,++cnt[v];
33                 if(cnt[v]>n){flag=1;return ;}
34             }
35         }
36     }
37     // return 0;
38 }
39 int main(){
40     double Rab,Cab,Rba,Cba;
41     scanf("%d %d %d %lf",&n,&m,&s,&V);
42     for(int i=1,u,v;i<=m;i++){
43         scanf("%d %d %lf %lf %lf %lf",&u,&v,&Rab,&Cab,&Rba,&Cba);
44         e[u].pb(edge(v,Rab,Cab));
45         e[v].pb(edge(u,Rba,Cba));
46     }
47     flag=0;
48     spfa();
49     if(flag)puts("YES");
50     else puts("NO");
51     // system("pause");
52     return 0;
53 }
View Code

F - Wormholes

 POJ - 3259 

直接spfa判负圈。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<map>
 4 #include<vector>
 5 #include<string>
 6 #include<cstring>
 7 #include<queue>
 8 using namespace std;
 9 #define pb push_back
10 const int inf=0x3f3f3f3f;
11 const int N=6e2+5;  
12 const double eps=1e-10;
13 struct edge{int v,w;edge(int a,int b){v=a,w=b;}};
14 vector<edge>e[N];
15 int n,m,W;
16 bool flag;
17 bool inq[N];
18 int dis[N];
19 int cnt[N];
20 void spfa(){
21     for(int i=1;i<=n;i++)inq[i]=0,cnt[i]=0,dis[i]=inf;
22     queue<int>Q;
23     Q.push(1),inq[1]=1;dis[1]=0;
24     while(!Q.empty()){
25         int u=Q.front();Q.pop();inq[u]=0;
26         for(int i=0;i<e[u].size();i++){
27             int v=e[u][i].v,w=e[u][i].w;
28             if(dis[v]>dis[u]+w){
29             dis[v]=dis[u]+w;
30             if(inq[v])continue;
31             Q.push(v),inq[v]=1,++cnt[v];
32             if(cnt[v]>n){flag=1;return ;}
33             }
34         }
35     }
36 }
37 int main(){
38     int T;scanf("%d",&T);
39     while(T--){
40         scanf("%d %d %d",&n,&m,&W);
41         for(int i=1;i<=n;i++)e[i].clear();
42         for(int i=1,u,v,w;i<=m;i++){
43         scanf("%d %d %d",&u,&v,&w);
44         e[u].pb(edge(v,w));
45         e[v].pb(edge(u,w));
46         }
47         for(int i=1,u,v,w;i<=W;i++){
48         scanf("%d %d %d",&u,&v,&w);
49         e[u].pb(edge(v,-w));
50         }
51         flag=0;
52         spfa();
53         // cout<<"test"<<endl;
54         // for(int i=1;i<=n;i++)cout<<i<<" "<<dis[i]<<endl; 
55         // cout<<"test "<<dis[1]<<endl;
56         if(flag)puts("YES");
57         else puts("NO");
58     }    
59     // system("pause");
60     return 0;
61 }
View Code

G - MPI Maelstrom

 POJ - 1502 

无脑;

#include<cstdio>
#include<iostream>
#include<map>
#include<vector>
#include<string>
#include<cstring>
#include<queue>
#include<cstdlib>
#include<algorithm>
using namespace std;
#define pb push_back
const int inf=0x3f3f3f3f;
const int N=1e2+5;
int gp[N][N];
int n;
void floyd(){
    for(int k=1;k<=n;k++){
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
            // gp[i][j]=min(gp[i][j])
            if(gp[i][j]>gp[i][k]+gp[k][j])
            gp[i][j]=gp[i][k]+gp[k][j];
            }
        }
    }
}
char s[1000];
int main(){
    while(~scanf("%d",&n)){
    memset(gp,0,sizeof gp);
    for(int i=1;i<=n;i++)gp[i][i]=0;
    for(int i=2;i<=n;i++){
        for(int j=1;j<=i-1;j++){
            scanf("%s",s);
            int a;
            if(s[0]=='x')a=inf;
            else  a=atoi(s);
        gp[j][i]=gp[i][j]=a;
        }
    }
    floyd();
    // int ans= * max_element(gp+1+n,gp+n*n);
    int ans=0;
    for(int i=1;i<=n;i++){
        // for(int j=1;j<=n;j++){
            if(gp[1][i]!=inf)ans=max(ans,gp[1][i]);
        // }
    }   
    printf("%d
",ans);
    }
    // system("pause");
    return 0;
}
View Code

H - Cow Contest

 POJ - 3660 

就是说n个人之间有着相互关系,问你能有几个确定排名。

开始自然想拓扑,但不好解决。

考虑传递闭包,如果a比b牛逼,b比c牛逼,那么a比c牛逼。

如果说一个点,和其他n-1个点关系明确,那么这个点就是明确的。

#include<cstdio>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
typedef long long ll;
#define pb push_back
const int inf=0x3f3f3f3f;
const ll mod=1e9+7;
const int N=1e2+6;
int gp[N][N];
    int n,m;
void floyd(){
    for(int k=1;k<=n;k++){
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                gp[i][j]|=(gp[i][k])&(gp[k][j]);
            }
        }
    }
}
int main(){
    scanf("%d %d",&n,&m);
    memset(gp,0,sizeof gp);
    for(int i=1,u,v;i<=m;i++){
        scanf("%d %d",&u,&v);
    gp[u][v]=1;
    }
    floyd();
    int ans=0;
    for(int i=1;i<=n;i++){
        int sum=0;
        for(int j=1;j<=n;j++){
            if(gp[i][j]||gp[j][i])sum++;
        }
        if(sum==n-1)ans++;
    }
    printf("%d
",ans);
    // for(int i=1;i<=n;i++)scanf("%d",&a[i]);



    // system("pause");
    return 0;
}
View Code

I - Arbitrage

 POJ - 2240 

套利:就是说一个货币,和其他货币不断交换后,最后变多了。问你有没有套利。

开始想dfs,感觉没啥毛病,但就是不对。

考虑最短路维护最大的交换钱,最后判断dis[1]即可。

#include<cstdio>
#include<iostream>
#include<map>
#include<vector>
#include<string>
#include<cstring>
using namespace std;
const int N=1e2+5;
#define pb push_back
char s[N][N],s1[N],s2[N];
const double eps=1e-8;
int n,m;
double gp[N][N];
void floyd(){
    for(int k=1;k<=n;k++){
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
            if(gp[i][j]<gp[i][k]*gp[k][j])
            gp[i][j]=gp[i][k]*gp[k][j];
            }
        }
    }
}
map<string,int>mp;
int main(){
    int cas=0;
    while(~scanf("%d",&n),n){
        mp.clear();
        for(int i=1;i<=n;i++)scanf("%s",s[i]),mp[ s[i] ]=i,gp[i][i]=1.0;
        memset(gp,1,sizeof gp);
        scanf("%d",&m);
        for(int i=1,u,v;i<=m;i++){
            double w;
            scanf("%s %lf %s",s1,&w,s2);
            // cout<<"test :"<<s1<<" "<<s2<<endl;
            u=mp[s1];v=mp[s2];
            gp[u][v]=w;
        }
        floyd();
        // for(int i=1;i<=n;i++){
        //     for(int j=1;j<=n;j++){
        //         cout<<i<<" "<<j<<" "<<gp[i][j]<<endl;
        //     }
        // }
        bool flag=0;
        for(int i=1;i<=n;i++){
            if(gp[i][i]>1){flag=1;break;}
        }

        printf("Case %d: ",++cas);
        if(flag)puts("Yes");
        else puts("No");
    }
    // system("paus?e");// bool vis[N],flag;
    return 0;

}
// 3
// USDollar
// BritishPound
// FrenchFranc
// 3
// USDollar 0.5 BritishPound
// BritishPound 10.0 FrenchFranc
// Frenc0hFranc 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
View Code

J - Invitation Cards

 POJ - 1511 

题意:求1到其他点的最短路和,以及其他点到1点最短路之和,

直接无脑跑是不行的,寻求问题转化。

就是说要找其他点到1点的最短路,把边反过来更新。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<map>
 4 #include<vector>
 5 #include<string>
 6 #include<cstring>
 7 #include<queue>
 8 #include<cstdlib>
 9 #include<algorithm>
10 using namespace std;
11 #define pb push_back
12 #define fi first
13 #define se second
14 typedef long long ll;
15 const int inf=0x3f3f3f3f;
16 const int N=1e6+5;
17 int n,m;
18 struct edge{int v;ll w;edge(int a,long long  b){v=a;w=b;}};
19 vector<edge>e[N];
20 struct mp{int x,y;long long z;};
21 vector<mp>maps;
22 ll ans;
23 long long dis[N];
24 bool inq[N];
25 void spfa(){
26     for(int i=1;i<=n;i++)dis[i]=inf,inq[i]=0;
27     queue<int>Q;
28     Q.push(1),inq[1]=1,dis[1]=0;
29     while(!Q.empty()){
30         int u=Q.front();Q.pop();inq[u]=0;
31         for(int i=0;i<e[u].size();i++){
32             int v=e[u][i].v;long long w=e[u][i].w;
33             if(dis[v]>dis[u]+w){
34             dis[v]=dis[u]+w;
35             if(!inq[v])Q.push(v),inq[v]=1;
36         }
37     }
38     }
39     for(int i=1;i<=n;i++)ans+=dis[i];
40 }
41 int main(){
42     int T;scanf("%d",&T);
43     while(T--){
44     scanf("%d %d",&n,&m);
45     maps.clear();
46     ans=0;
47     int u,v;ll w;
48     for(int i=1;i<=n;i++)e[i].clear();
49     for(int i=1;i<=m;i++){
50     mp tmp;
51     scanf("%d %d %lld",&tmp.x,&tmp.y,&tmp.z);
52     maps.pb(tmp);
53     }
54     for(int i=0;i<m;i++){
55         int u=maps[i].x,v=maps[i].y;long long w=maps[i].z;
56         e[u].pb(edge(v,w));
57     }
58     spfa();
59     for(int i=1;i<=n;i++)e[i].clear();
60     for(int i=0;i<m;i++){
61         int u=maps[i].x,v=maps[i].y;long long w=maps[i].z;
62         e[v].pb(edge(u,w));
63     }
64     spfa();
65     printf("%lld
",ans);
66     }
67     // system("pause");
68     return 0;
69 }
View Code

 K:

裸的差分约束,long long 数据。

#include<cstdio>
#include<iostream>
#include<map>
#include<vector>
#include<string>
#include<cstring>
#include<queue>
// #include<cstdlib>
#include<algorithm>
using namespace std;
#define pb push_back
#define fi first
#define se second
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=3e4+5;
// int n,m;
// [N];
// void spfa(){
//     for(int i=1;i<=n;i++)inq[i]=0,dis[i]=inf;
//     queue<int>Q;
//     Q.push(1);inq[1]=1;dis[1]=0;
//     while(!Q.empty()){
//         int u=Q.front();Q.pop();inq[u]=0;
//         for(int i=0;i<e[u].size();i++){
//             int v=e[u][i].v,w=e[u][i].w;
//             if(dis[v]>dis[u]+w){
//                 dis[v]=dis[u]+w;
//                 if(!inq[v])Q.push(v),inq[v]=1;
//             }
//         }
//     }
// }
int head[N],cnt;//cnt main里初始化为0,head main初始化为-1
struct edge{int to,w,next;}e[N*10];//注意有重边,乘10
struct node{int id,dis;//id点,dis距离
    node(int x,int y){id=x,dis=y;}
    friend bool operator<(node a,node b){
    return a.dis>b.dis;//距离小的出队
    }
};
void add(int u,int v,int w){//加边
    e[cnt].to=v,e[cnt].w=w,e[cnt].next=head[u],head[u]=cnt++;
}
int dis[N];
bool done[N];//dis记录距离,done记录是否找到最短路
int n,m;
void dijkstra(){
    int s=1;//s起点 视情况调整
    for(int i=1;i<=N;i++)dis[i]=inf,done[i]=0;
    dis[s]=0;
    priority_queue<node>Q;
    Q.push(node(s,0));
    while(!Q.empty()){
    int x=Q.top().id;
    Q.pop();
    if(done[x])continue;
    done[x]=1;
    for(int i=head[x];i!=-1;i=e[i].next){
    int y=e[i].to;
    if(done[y])continue;
    if(dis[y]>dis[x]+e[i].w)dis[y]=dis[x]+e[i].w;//更新距离
    Q.push(node(y,dis[y]));
    }
    }
}
int main(){
    memset(head,-1,sizeof head);
    scanf("%d %d",&n,&m);
    for(int i=1,u,v,w;i<=m;i++){
        scanf("%d %d %d",&u,&v,&w);
        // e[u].pb(edge(v,w));
        add(u,v,w);
    }
    dijkstra();
    // int ans= * max_element(dis+1,dis+1+n);
    int ans=0;
    for(int i=1;i<=n;i++)ans=max(ans,dis[i]);
    printf("%d
",ans);
    // system("pause");
    return 0;
}
View Code

L:傻逼题,样例都没法测

M - 昂贵的聘礼

 POJ - 1062 

解法:挺简单的,就是没考虑限制,按照区间进行枚举即可,蛋疼的g++过不了。

#include<cstdio>
#include<vector>
#include<queue>
#include<iostream>
#include<cstring>
using namespace std;
const int N=1e2+5;
typedef long long ll;
const int inf=0x3f3f3f3f;
#define pb push_back
int n,m;
int  gp[N][N];
int  lim[N];
int val[N],dis[N];bool inq[N],can[N];
int spfa(){
    for(int i=1;i<=n;i++)inq[i]=0,dis[i]=inf;
    queue<int>Q;
    Q.push(1),inq[1]=1;dis[1]=0;
    while(!Q.empty()){
        int u=Q.front();Q.pop();inq[u]=0;
        for(int i=1;i<=n;i++){
        if(dis[i]>dis[u]+gp[u][i]&&can[i]){
        dis[i]=dis[u]+gp[u][i];
        if(!inq[i])Q.push(i),inq[i]=1;
        }
        }
    }
    int  cur=inf;
    for(int i=1;i<=n;i++){
        cur=min(cur,dis[i]+val[i]);
    }
    return cur;
}
int main(){
    scanf("%d %d",&m,&n);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(i==j)gp[i][j]=0;
            else gp[i][j]=inf;
        }
    }
    for(int i=1,q;i<=n;i++){
        scanf("%d %d %d",&val[i],&lim[i],&q);
        for(int j=1,v;j<=q;j++){
            int  w;
            scanf("%d %d",&v,&w);
            // e[i].pb(edge(v,w));
            gp[i][v]=w;
        }
    }
    int  ans=inf;
    for(int i=0;i<=m;i++){
    memset(can,0,sizeof can);
    for(int j=1;j<=n;j++){
    if(lim[j]<=lim[1]+i&&lim[j]>=lim[1]-m+i)can[j]=1;
      // spfa();
    ans=min(ans,spfa() );
    }
    }
    printf("%lld
",ans);   
    // system("pause");
    return 0;
}
View Code

R - 0 or 1

 HDU - 4370 

题意:给你一个矩阵C,让你求一个矩阵01矩阵X,

满足:.X 12+X 13+...X 1n=1 ,

X 1n+X 2n+...X n-1n=1

∑X ki (1<=k<=n)=∑X ij (1<=j<=n).

使得

最小

 

怎么理解这题呢?想象最短路,到有一条边,表示到有一条有向边,表示这条边是否存在。
对于条件:点的出度为,点的入度为,其他点入度等于出度。
那么有两种情况满足:,
1.   跑一遍到的最短路,满足条件。
2   1 形成一个环,n 形成一个环,满足条件
。注意:更新最短路源点不能设为0,而是inf,不然没法更新最短路。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MOD=1e9+7;
#define pb push_back
const int inf=0x3f3f3f3f;
int n;
const int N=3e2+5;
int dis[N],C[N][N];bool inq[N];
void spfa(int s){
    for(int i=1;i<=n;i++)inq[i]=0,dis[i]=inf;
    queue<int>Q;Q.push(s);inq[s]=1;
    for(int i=1;i<=n;i++){
        if(i==s)dis[i]=inf;
        else dis[i]=C[s][i],Q.push(i);
    }
    while(!Q.empty()){
        int u=Q.front();Q.pop();inq[u]=0;
        for(int i=1;i<=n;i++){
            if(dis[i]>dis[u]+C[u][i]){
                dis[i]=dis[u]+C[u][i];
                if(!inq[i])Q.push(i),inq[i]=1;
            }
        }
    }
}
int main(){
    while(~scanf("%d",&n)){

        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++)
                scanf("%d",&C[i][j]);
        }
        spfa(1);
        int ans=dis[n];
        int d1=dis[1];
        spfa(n);
        int d2=dis[n];
        ans=min(ans,d1+d2);
        printf("%d
",ans);
    }

    // system("pause");
    return 0;
}
View Code
想的太多,做的太少;
原文地址:https://www.cnblogs.com/littlerita/p/12610546.html