zoukankan      html  css  js  c++  java
  • [POI2012]FES-Festival

    题意

    对于一些数字,有两种限制;1:a+1=b;2:a<=b;

    求这些数字最多有多少不同数值。

    对于100%的数字n<=600,限制<=1e5

    题解

    可以得到将限制转化:1:b<=a+1<=b-->b<=a+1,a<=b-1

    2:a<=b+0

    那么可以建出边,跑最短路;

    找负环时,如果用bfs版spfa会发现出发点可能和负环不连通。

    于是先tarjan找出联通块,建虚拟源点连向每个联通块,再跑spfa。

    注意到联通块之间只用边权为0的边连接,这些边是由第二个限制产生,即a<=b,但这并不确定绝对大小,所以对于b所在联通块可以无限增大值,这样就可以使得两者的值无交集,那么就可以使得有更多取值。

    对于同一联通块,里面的边只有1或-1,所以里面的取值是连续的,所以取值数量就是最大的差值+1.

    这里主要想记一种floyed求负环;

    秩序在跑出floyed后判断f[i][i]是否为0,设初值为0.

    在floyed时,判断是否在同一联通块和是否有边可以做到强力剪枝,快到飞起。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn=605;
    const int maxm=100005;
    int n,m1,m2;
    int mx[maxn],ans;
    int cur,cnt,dfn[maxn],low[maxn];
    int top,sta[maxn],res[maxn];
    bool tag[maxn];
    int dis[maxn][maxn];
    vector<pair<int,int> >e[maxn];
    
    void tarjan(int u){
        low[u]=dfn[u]=++cur;
        sta[++top]=u;
        tag[u]=true;
        
        for(unsigned int i=0;i<e[u].size();i++){
          int v=e[u][i].first;
          if(!dfn[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
          }
          else if(tag[v]) low[u]=min(low[u],dfn[v]);
        }
        
        if(dfn[u]==low[u]){
          cnt++;
          int t;
          do{
              t=sta[top--];
              res[t]=cnt;
              tag[t]=false;
          }while(t!=u);
        }
    }
    
    int main(){
        scanf("%d%d%d",&n,&m1,&m2);
        
        memset(dis,0x3f3f,sizeof(dis));
        for(int i=1;i<=n;i++) dis[i][i]=0;
        
        for(int i=1;i<=m1;i++){//a+1=b;
            int a,b;
            scanf("%d%d",&a,&b);
            //b<=a+1<=b
            e[a].push_back(make_pair(b,1));
            e[b].push_back(make_pair(a,-1));
            dis[a][b]=min(dis[a][b],1);
            dis[b][a]=min(dis[b][a],-1);
        }
        
        for(int i=1;i<=m2;i++){//a<=b
            int a,b;
            scanf("%d%d",&a,&b);
            e[b].push_back(make_pair(a,0));
            dis[b][a]=min(dis[b][a],0);
        }
        
        for(int i=1;i<=n;i++)
         if(!dfn[i]) tarjan(i);
         
        for(int k=1;k<=n;k++)
         for(int i=1;i<=n;i++)
          if(res[i]==res[k]&&dis[i][k]!=dis[0][0])//第二句剪枝快了不知道多少倍 
           for(int j=1;j<=n;j++)
            if(res[i]==res[j]&&dis[k][j]!=dis[0][0])
            dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
            
        for(int i=1;i<=n;i++) if(dis[i][i]) {printf("NIE");exit(0);}
        
        for(int i=1;i<=n;i++)
         for(int j=1;j<=n;j++)
          if(res[i]==res[j])
           mx[res[i]]=max(mx[res[i]],dis[i][j]);
           
        for(int i=1;i<=cnt;i++) ans+=mx[i]+1;
        printf("%d",ans);
    }
    View Code
  • 相关阅读:
    Eclipse 导入项目乱码问题(中文乱码)
    sql中视图视图的作用
    Java基础-super关键字与this关键字
    Android LayoutInflater.inflate(int resource, ViewGroup root, boolean attachToRoot)的参数理解
    Android View和ViewGroup
    工厂方法模式(java 设计模式)
    设计模式(java) 单例模式 单例类
    eclipse乱码解决方法
    No resource found that matches the given name 'Theme.AppCompat.Light 的完美解决方案
    【转】使用 Eclipse 调试 Java 程序的 10 个技巧
  • 原文地址:https://www.cnblogs.com/sto324/p/11228144.html
Copyright © 2011-2022 走看看