解题思路
把“A不小于B”和“A 不大于B”转换变成“A大于等于B”和“A小于等于B ”
那如果
A
<
B
A<B
A<B那么B可以为
A
+
1
A+1
A+1,如果有等于,那就
B
=
A
。
B
<
A
B=A。B<A
B=A。B<A 和B小于等于A 的关系同理。
我们发现会有环所以用 T a r j a n Tarjan Tarjan缩点,把 A < B A<B A<B或 A < = B A<=B A<=B连一条A到B的有向边,然后缩点缩在一起,(就是亮度相同)。
但一个环中如果有小于,那就会有矛盾,因为你要求亮度相同,但这条边却是小于,判断这样的情况然后直接输出 “ − 1 ” “-1” “−1”。
然后就在拓扑序列里 d p dp dp 转移的时候,判断下边的类型,小于就是原来的边 + 1 +1 +1,否则就是原来的
代码
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
int n,m,u,v,p,k,tot,t,top;
long long ans;
int h[100010],head[100010],dfn[100010],low[100010],st[100010],c[100010],sum[100010],ru[100010],dis[100010];
struct c{
int x,w,next;
}a[100010];
struct cc{
int x,w,next;
}b[100010];
void add(int x,int y,int w){
a[++k].x=y;
a[k].next=h[x];
a[k].w=w;
h[x]=k;
}
void Add(int x,int y,int w){
b[++k].x=y;
b[k].next=head[x];
b[k].w=w;
head[x]=k;
}
void Tarjan(int x)
{
st[++top]=x;
dfn[x]=low[x]=++t;
for(int i=h[x];i;i=a[i].next)
{
int y=a[i].x;
if(!dfn[y])
{
Tarjan(y);
low[x]=min(low[x],low[y]);
}
else if(!c[y])
low[x]=min(low[x],low[y]);
}
if(dfn[x]==low[x])
{
tot++;
while(st[top+1]!=x)
{
c[st[top]]=tot;
sum[tot]++;
top--;
}
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&p,&u,&v);
if(p==1){add(u,v,0);add(v,u,0);}
if(p==2)add(u,v,1);
if(p==3)add(v,u,0);
if(p==4)add(v,u,1);
if(p==5)add(u,v,0);
}
for(int i=1;i<=n;i++)
if(!dfn[i])
Tarjan(i);
k=0;
for(int i=1;i<=n;i++)
{
for(int j=h[i];j;j=a[j].next)
{
int y=a[j].x;
if(c[i]!=c[y])
{
Add(c[i],c[y],a[j].w);
ru[c[y]]++;
}
else if(a[j].w==1)
{
printf("-1");
return 0;
}
}
}
queue<int>q;
for(int i=1;i<=tot;i++)
{
dis[i]=1;
if(!ru[i])q.push(i);
}
while(!q.empty())
{
int x=q.front();
q.pop();
ans+=dis[x]*sum[x];
for(int i=head[x];i;i=b[i].next)
{
int y=b[i].x;
dis[y]=max(dis[y],dis[x]+b[i].w);
ru[y]--;
if(!ru[y])q.push(y);
}
}
printf("%lld",ans);
}