• [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
  • 相关阅读:
    dapper+linq+json+ztree构建树
    ubuntu,从一个新用户,要转到新用户的命令行操作
    OC本学习笔记Foundatio框架集
    无法Debug SQL: Unable to start T-SQL Debugging. Could not attach to SQL Server process on
    Struts2 + uploadify 多文件上传完整的例子!
    How use Instruments and display the console in Command Lines applications
    Android ActionBar详解(二):ActionBar实现Tabs标签以及下拉导航
    Android ActionBar详解(一):ActionBar概述及其创建
    Android Fragment详解(六):Fragement示例
    Android Fragment详解(五):Fragment与Activity通讯
  • 原文地址:https://www.cnblogs.com/sto324/p/11228144.html
Copyright © 2020-2023  润新知