zoukankan      html  css  js  c++  java
  • bzoj5470 / P4578 [FJOI2018]所罗门王的宝藏(差分约束)

    P4578 [FJOI2018]所罗门王的宝藏

    错解:

    设第$i$行上的值改变了$r1[i]$,第$j$列上的值改变了$r2[i]$

    显然密码$(i,j,c)=r1[i]+r2[j]$

    对于同一列上的两个密码$(i_{1},j,c_{1}),(i_{2},j,c_{2})$,它们的差值即为$c_{1}-c_{2}=r1[i_{1}]-r1[i_{2}]$

    同一行上的同理。

    这样我们就可以确定$r1[i],r2[j]$之间的关系,并以此判断

    那么对于每组数据,我们可以$O(k^2)$两两枚举宝石,用上述方法判断即可。

    同一个地方可能有两颗宝石

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cctype>
     5 using namespace std;
     6 void read(int &x){
     7     char c=getchar();x=0;bool f=1;
     8     while(!isdigit(c)) f=(f&&c!='-'),c=getchar();
     9     while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
    10     x=f?x:-x;
    11 }
    12 #define N 1005
    13 int n,m,k,x[N],y[N],v[N],d1[N][N],d2[N][N];
    14 bool w1[N][N],w2[N][N],ok;
    15 int ask(int i,int j,int c){
    16     if(c) return y[i]<y[j]?v[i]-v[j]:v[j]-v[i];
    17     else  return x[i]<x[j]?v[i]-v[j]:v[j]-v[i];
    18 }
    19 bool check(int i,int j){
    20     if(x[i]==x[j]&&y[i]==y[j]&&v[i]!=v[j]) return 0;//同个位置两颗宝石
    21     if(y[i]==y[j]){
    22         if(w1[x[i]][x[j]]&&d1[x[i]][x[j]]!=ask(i,j,0)) return 0;
    23         d1[x[i]][x[j]]=d1[x[j]][x[i]]=ask(i,j,0);
    24         w1[x[i]][x[j]]=w1[x[j]][x[i]]=1;
    25     }
    26     if(x[i]==x[j]){
    27         if(w2[y[i]][y[j]]&&d2[y[i]][y[j]]!=ask(i,j,1)) return 0;
    28         d2[y[i]][y[j]]=d2[y[j]][y[i]]=ask(i,j,1);
    29         w2[y[i]][y[j]]=w2[y[j]][y[i]]=1;
    30     }return 1;
    31 }
    32 int main(){
    33     int T;read(T);
    34     while(T--){
    35         memset(d1,0,sizeof(d1));
    36         memset(d2,0,sizeof(d2));
    37         memset(w1,0,sizeof(w1));
    38         memset(w2,0,sizeof(w2));
    39         read(n);read(m);read(k);ok=1;
    40         for(int i=1;i<=k;++i)
    41             read(x[i]),read(y[i]),read(v[i]);
    42         for(int i=1;i<=k&&ok;++i)
    43             for(int j=i+1;j<=k&&ok;++j)
    44                 ok=check(i,j);
    45         printf(ok?"Yes
    ":"No
    ");
    46     }return 0;
    47 }
    View Code

    上面这个做法被评论hack了

    今天终于用差分约束过掉了

    发现对于$(x1,y1,w1),(x2,y2,w2)$

    如果$x1==x2$,那么可以得到$y1,y2$之间的操作差值$v[y1]-v[y2]=w1-w2$

    于是通过这样在行和列分别建图

    跑spfa判负环

    记住多组数据,该清空的全清空掉

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define N 1005
    #define M 2000005
    int T,n,m,k,u[N],v[N],w[N],f1[N],f2[N];
    bool vis1[N],vis2[N],ok;
    
    int Cnt1,hd1[N],nxt1[M],ed1[N],poi1[M],val1[M];
    void adde1(int x,int y,int v){
        nxt1[ed1[x]]=++Cnt1; hd1[x]=hd1[x]?hd1[x]:Cnt1;
        ed1[x]=Cnt1; poi1[Cnt1]=y; val1[Cnt1]=v;
    }
    void link1(int x,int y,int v){adde1(x,y,v),adde1(y,x,-v);}
    
    int Cnt2,hd2[N],nxt2[M],ed2[N],poi2[M],val2[M];
    void adde2(int x,int y,int v){
        nxt2[ed2[x]]=++Cnt2; hd2[x]=hd2[x]?hd2[x]:Cnt2;
        ed2[x]=Cnt2; poi2[Cnt2]=y; val2[Cnt2]=v;
    }
    void link2(int x,int y,int v){adde2(x,y,v),adde2(y,x,-v);}
    
    void spfa1(int x){
        if(vis1[x]) ok=1;
        if(ok) return ;
        vis1[x]=1;
        for(int i=hd1[x];i&&!ok;i=nxt1[i]){
            int to=poi1[i];
            if(f1[to]>f1[x]+val1[i])
                f1[to]=f1[x]+val1[i],spfa1(to);
        }
        vis1[x]=0;
    }
    void spfa2(int x){
        if(vis2[x]) ok=1;
        if(ok) return ;
        vis2[x]=1;
        for(int i=hd2[x];i&&!ok;i=nxt2[i]){
            int to=poi2[i];
            if(f2[to]>f2[x]+val2[i])
                f2[to]=f2[x]+val2[i],spfa2(to);
        }
        vis2[x]=0;
    }
    int main(){
        scanf("%d",&T);
        while(T--){
            scanf("%d%d%d",&n,&m,&k);
            f1[0]=f2[0]=ok=0;
            for(int i=1;i<=n;++i) f1[i]=2e9;
            for(int i=1;i<=m;++i) f2[i]=2e9;
            for(int i=1;i<=n;++i) adde1(0,i,0);//虚拟源点建图,防止图不连通
            for(int i=1;i<=m;++i) adde2(0,i,0);    
            for(int i=1;i<=k;++i){
                scanf("%d%d%d",&u[i],&v[i],&w[i]);
                for(int j=i-1;j;--j){
                    if(v[i]==v[j]) link1(u[i],u[j],w[j]-w[i]);
                    if(u[i]==u[j]) link2(v[i],v[j],w[j]-w[i]);
                }
            }
            spfa1(0); spfa2(0);
            puts(ok?"No":"Yes");
            for(int i=0;i<=n;++i) vis1[i]=hd1[i]=ed1[i]=0;
            for(int i=0;i<=m;++i) vis2[i]=hd2[i]=ed2[i]=0;
            for(int i=1;i<=Cnt1;++i) nxt1[i]=poi1[i]=0;
            for(int i=1;i<=Cnt2;++i) nxt2[i]=poi2[i]=0;
            Cnt1=Cnt2=0;
        }return 0;
    }
  • 相关阅读:
    洛谷 P1111 修复公路
    洛谷 P2320 [HNOI2006]鬼谷子的钱袋
    洛谷 P2023 [AHOI2009]维护序列
    洛谷 P1341 无序字母对(欧拉回路)
    洛谷 P1330 封锁阳光大学
    javaweb学习总结(二十三)——jsp自定义标签开发入门
    javaweb学习总结(二十二)——基于Servlet+JSP+JavaBean开发模式的用户登录注册
    javaweb学习总结(二十一)——JavaWeb的两种开发模式
    javaweb学习总结(二十)——JavaBean总结
    javaweb学习总结(十九)——JSP标签
  • 原文地址:https://www.cnblogs.com/kafuuchino/p/10082585.html
Copyright © 2011-2022 走看看