1. 程式人生 > >暑假集訓day5

暑假集訓day5

內容 size 負環 col ostream ace pop spa name

今天的主要內容為最小生成樹判負環差分約束系統

苗條的最小生成樹 poj3522

本題排序完枚舉最小邊,Kruskal跑n遍即可。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int INF=0x7fffffff;
inline int read(){
    int num=0,t=1;char c=getchar();
    while(c>9||c<0){if(c==-)t=-1;c=getchar();}
    
while(c>=0&&c<=9){num=(num<<3)+(num<<1)+c-0;c=getchar();} return num*t; } struct edge{int u,v,c;}e[5000]; int fa[5000],V,E; bool cmp(edge a,edge b){return a.c<b.c;} int find(int x){ if(fa[x]==x)return x; return fa[x]=find(fa[x]); } void unite(int x,int y){
int fx=find(x),fy=find(y); if(fx==fy)return; fa[fx]=fy; } int kruskal(){ sort(e+1,e+1+E,cmp);int ans=INF; for(int i=1;i<=E;i++){ for(int j=1;j<=V;j++)fa[j]=j;int cnt=V; for(int j=i;j<=E;j++) if(find(e[j].u)!=find(e[j].v)){ unite(e[j].u,e[j].v);
if(--cnt==1){ ans=min(ans,e[j].c-e[i].c);break; } } } if(ans==INF)ans=-1; return ans; } int main() { while(1){ V=read();E=read(); if(V==0)break; for(int i=1;i<=E;i++){ int u=read(),v=read(),c=read(); e[i]=(edge){u,v,c}; } printf("%d\n",kruskal()); } return 0; }

蟲洞 9018_1449

題目大意是給出m條正邊,w條負的,叫你判負環

#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read(){
    int num=0,t=1;char c=getchar();
    while(c>9||c<0){if(c==-)t=-1;c=getchar();}
    while(c>=0&&c<=9){num=(num<<3)+(num<<1)+c-0;c=getchar();}
    return num*t;
}
const int INF=1000000000;
struct edge{int v,c;};
vector<edge>g[1510];
int T,n,m,w,cnt[510],lev[510];
void solve(){
    queue<int>q;
    q.push(1);cnt[1]++;lev[1]=0;
    while(!q.empty()){
        int x=q.front();q.pop();
        if(cnt[x]>n){puts("YES");return;}
        for(int i=0;i<g[x].size();i++){
            edge y=g[x][i];
            if(lev[x]+y.c<lev[y.v]){
                lev[y.v]=lev[x]+y.c;
                q.push(y.v);cnt[y.v]++;
            }
        }
    }
    puts("NO");
}
int main()
{
    T=read();
    while(T--){
        n=read();m=read();w=read();
        for(int i=1;i<=n;i++)g[i].clear();
        for(int i=1;i<=n;i++)lev[i]=INF;
        memset(cnt,0,sizeof(cnt));
        for(int i=1;i<=m;i++){
            int u=read(),v=read(),c=read();
            g[u].push_back((edge){v,c});
            g[v].push_back((edge){u,c});
        }
        for(int i=1;i<=w;i++){
            int u=read(),v=read(),c=read();
            g[u].push_back((edge){v,-c});
        }
        solve();
    }
    return 0;
}

layout 9018_1456

本題在判負環的基礎上用了差分約束系統

#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read(){
    int num=0,t=1;char c=getchar();
    while(c>9||c<0){if(c==-)t=-1;c=getchar();}
    while(c>=0&&c<=9){num=(num<<3)+(num<<1)+c-0;c=getchar();}
    return num*t;
}
const int INF=1000000000;
struct edge{int v,c;};vector<edge>g[3010];
int T,n,m,w,cnt[1010],lev[1010];
void solve(){
    queue<int>q;q.push(1);cnt[1]++;lev[1]=0;
    while(!q.empty()){
        int x=q.front();q.pop();
        if(cnt[x]>n){if(lev[1]<0)puts("-1");else puts("-2");return;}
        for(int i=0;i<g[x].size();i++){
            edge y=g[x][i];
            if(lev[x]+y.c<lev[y.v]){lev[y.v]=lev[x]+y.c;q.push(y.v);cnt[y.v]++;}
        }
    }
    printf("%d\n",lev[n]);
}
int main()
{
    n=read();m=read();w=read();
    for(int i=1;i<=n;i++)lev[i]=INF,g[i].clear();
    memset(cnt,0,sizeof(cnt));
    for(int i=2;i<=n;i++)g[i].push_back((edge){i-1,0});
    for(int i=1;i<=m;i++){
        int u=read(),v=read(),c=read();
        g[u].push_back((edge){v,c});
    }
    for(int i=1;i<=w;i++){
        int u=read(),v=read(),c=read();
        g[v].push_back((edge){u,-c});
    }solve();
    return 0;
}

糖果BZOJ2330

本題思路和上題差不多

註意的時

是如果用vector的話由0向各個點的邊要從1——n連

~~~~~編表~~~~~~~~~~~~~~~~~~~~~~n——1連

我一不小心vector的連邊順序變成n——1 然後就T了

#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read(){
    int num=0,t=1;char c=getchar();
    while(c>9||c<0){if(c==-)t=-1;c=getchar();}
    while(c>=0&&c<=9){num=(num<<3)+(num<<1)+c-0;c=getchar();}
    return num*t;
}
const int INF=1000000000;
struct edge{int v,c;};
vector<edge>g[205010];queue<int>q;
int n,k,cnt[100010]={0},lev[100010]={0},du[100010]={0};
void add(int x,int y,int c){g[x].push_back((edge){y,c});}
bool solve(){
    q.push(0);cnt[0]++;lev[0]=0;
    while(!q.empty()){
        int x=q.front();q.pop();
        if(cnt[x]>n)return 1;
        for(int i=0;i<g[x].size();i++){
            edge y=g[x][i];
            if(lev[x]+y.c>lev[y.v]){
                lev[y.v]=lev[x]+y.c;
                q.push(y.v);cnt[y.v]++;
            }
        }
    }
    return 0;
}
int main()
{
    n=read();k=read();
    for(int i=1;i<=k;i++){
        int x=read(),a=read(),b=read();
        if(x==1){add(a,b,0),add(b,a,0);}
        else if(x==2){if(a==b){puts("-1");return 0;}add(a,b,1);}
        else if(x==3)add(b,a,0);
        else if(x==4){if(a==b){puts("-1");return 0;}add(b,a,1);}
        else add(a,b,0);
    }
    for(int i=1;i<=n;i++)add(0,i,1);
    if(solve()){puts("-1");return 0;}
    long long ans=0;
    for(int i=1;i<=n;i++)ans+=lev[i];
    printf("%lld\n",ans);
    return 0;
}

本文由Yzyet編寫,網址為www.cnblogs.com/Yzyet。非Yzyet同意,禁止轉載,侵權者必究。

暑假集訓day5