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;
}

原文地址:https://www.cnblogs.com/Arielzz/p/14923343.html