整理的算法模板:ACM算法模板總結(分類詳細版)
銀河中的恆星浩如煙海,但是我們只關注那些最亮的恆星。
我們用一個正整數來表示恆星的亮度,數值越大則恆星就越亮,恆星的亮度最暗是 1。
現在對於 N 顆我們關注的恆星,有 M 對亮度之間的相對關係已經判明。
你的任務就是求出這 N 顆恆星的亮度值總和至少有多大。
輸入格式
第一行給出兩個整數 N 和 M。
之後 M 行,每行三個整數 T, A, B,表示一對恆星(A, B)之間的亮度關係。恆星的編號從 1 開始。
如果 T = 1,說明 A 和 B 亮度相等。
如果 T = 2,說明 A 的亮度小於 B 的亮度。
如果 T = 3,說明 A 的亮度不小於 B 的亮度。
如果 T = 4,說明 A 的亮度大於 B 的亮度。
如果 T = 5,說明 A 的亮度不大於 B 的亮度。
輸出格式
輸出一個整數表示結果。
若無解,則輸出 -1。
數據範圍
N≤100000,M≤100000N≤100000,M≤100000
輸入樣例:
5 7
1 1 2
2 3 2
4 4 1
3 4 5
5 4 5
2 3 5
4 5 1
輸出樣例:
11
首先這道題可以用差分約束系統,用棧優化spfa求正環來做;但是,不是正解(畢竟棧優化spfa不是每次都可);
有向圖的強連通分量做法:
- 用tarjan求強連通分量跑圖,同時記錄每個連通分量的大小;
- 遍歷每一個點,然後對於不是一個強連通塊內的點進行縮點,建立新邊;
- 由於處理完的圖是有向無環圖,滿足拓撲序,那麼可以直接用遞推求最長路(因爲強連通分量的標號是在回溯的過程中進行的,是逆拓撲序,所以應該倒着遞推);
- 每個強連通塊內部兩兩之間值邊權一定爲0,否則會出現正環,也就是無解的情況;
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100010,M=N*6;
int n,m;
int h[N],hs[N],e[M],ne[M],w[M],idx;
int dfn[N],low[N],timestamp;
int stk[N],top;
bool in_stk[N];
int id[N],scc_cnt,size_scc[N];
int dis[N];
void add(int h[],int a,int b,int c)
{
//cout <<a<<" "<<b<<" "<<c<<endl;
e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}
void tarjan(int u)
{
dfn[u] = low[u] = ++ timestamp;
stk[ ++ top] = u, in_stk[u] = true;
for (int i = h[u]; ~i; i = ne[i])
{
int j = e[i];
if (!dfn[j])
{
tarjan(j);
low[u] = min(low[u], low[j]);
}
else if (in_stk[j]) low[u] = min(low[u], dfn[j]);
}
if (dfn[u] == low[u])
{
++ scc_cnt;
int y;
do {
y = stk[top -- ];
in_stk[y] = false;
id[y] = scc_cnt;
size_scc[scc_cnt] ++ ;
} while (y != u);
}
}
int main()
{
cin >>n>>m;
memset(h,-1,sizeof h);
memset(hs,-1,sizeof hs);
for(int i=1;i<=n;i++) add(h,0,i,1);
while (m -- )
{
int t, a, b;
cin >>t>>a>>b;
if (t == 1) add(h, b, a, 0), add(h, a, b, 0);
else if (t == 2) add(h, a, b, 1);
else if (t == 3) add(h, b, a, 0);
else if (t == 4) add(h, b, a, 1);
else add(h, a, b, 0);
}
for(int i=0;i<=n;i++)
{
if(!dfn[i]) tarjan(i);
}
bool f=true;
for(int i=0;i<=n;i++)
{
for(int j=h[i];~j;j=ne[j])
{
int k=e[j];
int a=id[i],b=id[k];
if(a!=b)
{
add(hs,a,b,w[j]);
}
else
{
if(w[j]>0)
{
f=false;
break;
}
}
}
if(!f) break;
}
//for(int i=1;i<=n;i++) cout <<id[i]<<" ";
if(!f) puts("-1"),exit(0);
for(int i=scc_cnt;i;i--)
{
for(int j=hs[i];~j;j=ne[j])
{
int k=e[j];
dis[k]=max(dis[k],dis[i]+w[j]);
}
}
ll ans=0;
for(int i=1;i<=scc_cnt;i++) ans+=(ll)dis[i]*size_scc[i];
cout <<ans<<endl;
}