• [Poi2012]Festival 变态 差分约束题


    题意

    有n个正整数X1,X2,...,Xn,再给出m1+m2个限制条件,限制分为两类:

    1. 给出a,b (1<=a,b<=n),要求满足Xa + 1 = Xb

    2. 给出c,d (1<=c,d<=n),要求满足Xc <= Xd

    在满足所有限制的条件下,求集合{Xi}大小的最大值。

    (自己注:求集合中不相同的的元素最多)

    solution

    (最后发现我tarjan写挂了......)

    1.建图

    Xa+1==Xb   ->   Xa+1<=Xb && Xa+1>=Xb

    Xc<=Xd   ->   Xc-Xd<=0

    2.floyd判负环(无解)&&求出两点之间的最短距离

    初始化mp[i][j]为INF

    记录下边后,把mp[i][j]=0

    floyd一遍,如果mp[i][i]<0,说明存在负环   (因为自己到自己不是0,肯定是走了一个负环回来,变小了,一定有负环嘛)

    3.tarjan缩点

    最后的ans是所有强联通分量 max-min+1 的和

    证明:

    对于每一个强连通分量,把他们连起来的一定是  w=0  的边

    如果不是,一定是{1,-1},但是两个点之间的边是相反关系,如果有1/-1边连强连通分量,那么一定有一条-1/1的边

    就不是两个强连通分量了

    而又因为边只有{0,1,-1}的边,所以从最小值~最大值一定是连续的,min又一定是0,因为有1/-1的边

    所以ans=∑(max-min+1)

     

    对于每一个强连通分量,求出最短路的最大值+1,即为此强连通分量对ans的贡献

    累加起来即可

     

      1 #include<iostream>
      2 #include<cstring>
      3 #include<cstdio>
      4 #define mem(a,b) memset(a,b,sizeof(a))
      5 using namespace std;
      6 const int N=606;
      7 struct son
      8 {
      9     int v,next;
     10 };
     11 son a1[200066];
     12 int first[200066],e;
     13 void addbian(int u,int v)
     14 {
     15     a1[e].v=v;
     16     a1[e].next=first[u];
     17     first[u]=e++;
     18 }
     19 
     20 int n,m1,m2;
     21 int u,o;
     22 int mp[N][N];
     23 int dfn[N],low[N],now,ans;
     24 int zhan[200006],he,flag[N];
     25 int ji[N],jinow;
     26 
     27 void jilu()
     28 {
     29     int temp=-0x7fffffff;
     30     for(int i=1;i<=jinow;++i)
     31       for(int j=1;j<=jinow;++j)
     32       {
     33             if(mp[ji[i]][ji[j]]>temp)
     34               temp=mp[ji[i]][ji[j]];
     35         }
     36     ans+=temp+1;
     37 }
     38 
     39 void tarjan(int x)
     40 {
     41     //printf("x=%d
    ",x);
     42     low[x]=dfn[x]=++now;
     43     flag[x]=1;zhan[++he]=x;
     44     for(int i=first[x];i!=-1;i=a1[i].next)
     45     {
     46         int temp=a1[i].v;
     47         //cout<<temp;
     48         if(dfn[temp]==-1)
     49         {
     50             tarjan(temp);
     51             if(low[x]>low[temp])
     52               low[x]=low[temp];
     53         }
     54         else
     55           if(flag[temp])
     56             if(low[x]>dfn[temp])
     57               low[x]=dfn[temp];
     58     }
     59     
     60     if(low[x]==dfn[x])
     61     {
     62         int temp;
     63         jinow=0;
     64         while(1)
     65         {
     66             temp=zhan[he--];flag[temp]=0;
     67             ji[++jinow]=temp;
     68             if(temp==x)
     69               break;
     70         }
     71         jilu();
     72     }
     73 }
     74 
     75 int floyd()
     76 {
     77     int temp;
     78     for(int i=1;i<=n;++i)
     79       mp[i][i]=0;
     80     for(int k=1;k<=n;++k)
     81       for(int i=1;i<=n;++i)
     82         for(int j=1;j<=n;++j)
     83         {
     84                 temp=mp[i][k]+mp[k][j];
     85           if(mp[i][j]>temp)
     86             mp[i][j]=temp;
     87             }
     88     for(int i=1;i<=n;++i)
     89       if(mp[i][i]<0)
     90         return 0;
     91     return 1;
     92 }
     93 
     94 int main(){
     95     
     96     //freopen("1.txt","r",stdin);
     97     
     98     mem(first,-1);
     99     mem(mp,0x3f);
    100     mem(dfn,-1);
    101     
    102     scanf("%d%d%d",&n,&m1,&m2);
    103     for(int i=1;i<=m1;++i)
    104     {
    105         scanf("%d%d",&u,&o);
    106         addbian(u,o);
    107         addbian(o,u);
    108         mp[u][o]=min(1,mp[u][o]);
    109         mp[o][u]=min(-1,mp[o][u]);//有可能会重复 
    110     }
    111     for(int i=1;i<=m2;++i)
    112     {
    113         scanf("%d%d",&u,&o);
    114         addbian(o,u);
    115         mp[o][u]=min(0,mp[o][u]);
    116     }
    117     if(floyd()==0)
    118     {
    119         printf("NIE
    ");
    120         return 0;
    121     }
    122 //    cout<<0;
    123     for(int i=1;i<=n;++i)
    124       if(dfn[i]==-1)
    125         tarjan(i);
    126     
    127     cout<<ans<<endl;
    128     //while(1);
    129     return 0;
    130 }
    code

     

     

  • 相关阅读:
    jQuery EasyUI API 中文文档 数字框(NumberBox)
    jQuery EasyUI API 中文文档 数值微调器(NumberSpinner)
    jQuery EasyUI API 中文文档 日期时间框(DateTimeBox)
    jQuery EasyUI API 中文文档 微调器(Spinner)
    jQuery EasyUI API 中文文档 树表格(TreeGrid)
    jQuery EasyUI API 中文文档 树(Tree)
    jQuery EasyUI API 中文文档 属性表格(PropertyGrid)
    EntityFramework 数据操作
    jQuery EasyUI API 中文文档 对话框(Dialog)
    jQuery EasyUI API 中文文档 组合表格(ComboGrid)
  • 原文地址:https://www.cnblogs.com/A-LEAF/p/7351610.html
Copyright © 2020-2023  润新知