luogu 2294 狡猾的商人 带权并查集

此题做法多啊

带权并查集,区间dp,前缀和,差分约束

1.自己写的前缀和, 11

#include<bits/stdc++.h>
#define rep(i,x,y) for(register int i=x;i<=y;i++)
using namespace std;
const int N=105;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;}
int T,n,m,l,r,v,sum,s[N];
int main(){
    T=read();
    while(T--){
        int fg=1;
        n=read();m=read();
        rep(i,1,m){
            l=read();r=read();v=read();
            sum=s[r]-s[l-1];
            if(sum==0) s[r]=s[l-1]+v;
            else if(sum&&sum!=v){printf("false\n");fg=0;break;}}
        if(fg) printf("true\n");
    }return 0;
}

2.自己写的区间dp

#include<bits/stdc++.h>
#define rep(i,x,y) for(register int i=x;i<=y;i++)
using namespace std;

inline int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;}
const int N=105;
int T,n,m,x,y,z,p,f[N][N];
int main(){
    T=read();
    while(T--){
        n=read();m=read();
        rep(i,1,m){
            x=read();y=read();z=read();
            f[x][y]=z;}
        p=1;
        for(int i=1;i<n;i++)if(p)
        for(int j=i+1;j<=n;j++)if(p)
        for(int k=i;k<j;k++)if(p)
        if(f[i][k]&&f[k+1][j])
            if(f[i][j]&&f[i][j]!=f[i][k]+f[k+1][j]){
                p=0;break;}
            else f[i][j]=f[i][k]+f[k][j];
        if(p==0) printf("false\n");
        else printf("true\n");
    }return 0;
}

3.区间dp  100

注意枚举时的方向,此题第二层为逆序(没有明白啊啊啊)

#include<bits/stdc++.h>
using namespace std;

inline int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;}
const int N=105;
int f[N][N],w,n,m,p,s,t,v;
int main(){
    w=read();
    while(w--){
        memset(f,0,sizeof(f));
        n=read(),m=read();
        for(int i=1;i<=m;i++){
            s=read(),t=read(),v=read();
            f[s][t]=v;}
        p=1;
        for(int i=2;i<=n;i++)if(p)              
        for(int j=i-1;j>=1;j--)if(p)             
        for(int k=j;k<i;k++)    
        if(f[j][k]&&f[k+1][i]){
            if(f[j][i]&&f[j][i]!=f[j][k]+f[k+1][i])
            {p=0;break;}
            else f[j][i]=f[j][k]+f[k+1][i];}
        if(p==0) printf("false\n");
        else printf("true\n");
    }
    return 0;
}

4.带权并查集

Attention!!!!!

f,ff提前取出来,不明原因,惨痛的教训。。。问提交满了一整页是怎样的感受

#include<bits/stdc++.h>
#define rep(i,x,y) for(register int i=x;i<=y;i++)
#define dec(i,x,y) for(register int i=x;i>=y;i--)
#define int long long
using namespace std;
const int N=1050;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;}
int T,n,m,x,y,z,fg,xx,yy,fa[N],cha[N];
int find(int x){
    if(fa[x]==x) return x;
    int f=fa[x],ff=find(fa[x]);cha[x]+=cha[f];
    //先推直接父亲权值,再路径压缩 
    fa[x]=ff;return ff;
} 
signed main(){
    T=read();
    while(T--){
        fg=1;n=read();m=read();
        rep(i,0,n) fa[i]=i,cha[i]=0;
        rep(i,1,m){
            x=read();y=read();z=read();x--;
            xx=find(x),yy=find(y);
            if(xx!=yy){
                fa[yy]=xx,cha[yy]=cha[x]+z-cha[y];}
            //此处 y连接在x 的子树上,y的深度大 
            else 
            if(cha[y]-cha[x]!=z) fg=0;
        }if(fg) printf("true\n");else printf("false\n");
    }
}

5.差分约束+spfa判断(实在不想写这道题了啊啊啊)

#include <cstdio>
#include <vector>
using namespace std;

const int maxn = 105;
const int maxm = 1005;

struct node{
    int to, val;
};
vector<node> e[maxn];
int t, n, m, dis[maxn];
bool vis[maxn], flag;

void SPFA(int x){ \\其实就是 DFS
    vis[x] = 1;
    for(int i = 0; i < e[x].size(); i++){
        node v = e[x][i];
        if(dis[v.to] > dis[x] + v.val){
            if(vis[v.to]){flag = 1; return;}
            dis[v.to] = dis[x] + v.val;
            SPFA(v.to);
        }
    }
    vis[x] = 0;
    return;
}
int main(){
    scanf("%d", &t);
    while(t--){
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= m; i++){
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            e[u-1].push_back((node){v, w});
            e[v].push_back((node){u-1, -1*w}); //建图
        }
        for(int i = 0; i <= n; i++){
            dis[i] = 0;
            SPFA(i);
            if(flag) { break;}
        }
        if(flag) printf("false\n");
        else printf("true\n");
        for(int i = 0; i <= n; i++){ \\记得在判断完每一组之后复位
            vis[i] = 0;
            dis[i] = 0;
            e[i].clear();
        }
        flag = 0;
    }
    return 0;
}

 

posted @ 2018-09-04 10:50  ASDIC减除  阅读(178)  评论(0编辑  收藏  举报