• P3530 [POI2012]FES-Festival


    Portal

    一道差分约束的好体。

    • 限制条件 1 ((A) 的成绩正好比 (B) 快 1 秒)

    (dis[a][b]=1)(dis[b][a]=−1)。(双向边适用于定量比较)

    • 限制条件 2 ((C) 的成绩不比 (D) 的差)

    (dis[b][a] = 0) (单向边适用于定性比较)

    要求最多能拿到的成绩种数;

    因为图存的是两点的最大差值,所以对于图中的强联通分量来说,任意两点的差值是确定的,所以在强联通分量中求出一条最长的两点之间的最短路 + 1,就是这个强联通分量中的答案

    统计完强联通分量的答案之后,对图进行缩点,因为条件一可以成自环,所以剩下的图是 0 边连接各强联通分量,所以每个强联通分量之间都是大于等于关系,所以可以无限的扩大,这些边就可以忽略了;

    然后直接单独统计每个强联通分量的答案求和就好了

    code

    /*
    work by:Ariel_
    */
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <queue>
    #include <stack>
    using namespace std;
    const int N = 610;
    int read(){
        int x = 0,f = 1; char c = getchar();
        while(c < '0'||c > '9') {if(c == '-') f = -1; c = getchar();}
        while(c >= '0' && c <= '9') {x = x*10 + c - '0'; c = getchar();}
        return x*f;
    }
    int n, m1, m2, dis[N][N], dfn[N], id[N], tot, vis[N], low[N], cnt, val[N], k;
    stack<int> s;
    bool opt;
    void tarjan(int x) {
    	dfn[x] = low[x] = ++tot, vis[x] = 1;
    	s.push(x);
    	for (int i = 1; i <= n; i++) {
    	    if(dis[x][i] <= 1) {
    	       if(!dfn[i]) {
    	       	  tarjan(i);
    	       	  low[x] = min(low[x], low[i]);
    		   }
    		   else if(vis[i]) low[x] = min(dfn[i], low[x]);
    		}
    	}
    	if(low[x] == dfn[x]) {
    	    do{
    	       k = s.top(), s.pop();
    		   vis[k] = 0, id[k] = x; 
    		}while(k != x);
    	}
    } 
    int main(){
       n = read(), m1 = read(), m2 = read();
       memset(dis, 0x3f3f3f3f, sizeof dis);
       for (int i = 1, a, b; i <= m1; i++) {
       	  a = read(), b = read();
       	  dis[a][b] = min(dis[a][b], 1);
    	  dis[b][a] = min(dis[b][a], -1); 
       }
       for (int i = 1, a, b; i <= m2; i++) {
       	  a = read(), b = read();
       	  dis[b][a] = min(dis[b][a], 0);
       }
       for (int i = 1; i <= n; i++) dis[i][i] = 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 (id[i] != id[k] || dis[i][k] == 0x3f3f3f3f)  continue;
    		for (int j = 1; j <= n; j++) {
    		   if (id[i] != id[j]) continue;
    		   dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
    		}	  
    	  }
       } 
       for (int i = 1; i <= n; i++) {
       	  if (dis[i][i] < 0) {opt = 1; break;}
       	  for (int j = 1; j <= n; j++) if (id[i] == id[j])  val[id[i]] = max(val[id[i]], dis[i][j] + 1);      
       }
       if (opt) printf("NIE");
       else {
       	  int Ans = 0;
       	  for (int i = 1; i <= n; i++) Ans += val[i];
       	  printf("%d", Ans);
       }
       puts("");
       return 0;
    }
    
    
  • 相关阅读:
    Python--BeautifulSoup4丶Tag丶Xpath丶requests+re的基础学习及使用
    c#字符串字面量
    vim操作
    序列的方法
    python数值类型与序列类型
    Linux操作学习笔记1
    Jav的10个面向对象设计原则
    JAVA面向对象基础
    二进制 八进制 十六进制
    using 的故事
  • 原文地址:https://www.cnblogs.com/Arielzz/p/14923343.html
Copyright © 2020-2023  润新知