我的想法是连的边权是负的,然后spfa跑最短路(先不说会不会T)。将有关系的点看成连通块,对每个连通块分别加上一个数,使得每个连通块内求出来的解加上这个数大于等于1,为什么这样做会WA?
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#define N 100010
using namespace std;
bool vis[N];
int ans[N],cnt[N],minn,res,n,k;
long long tot;
vector<pair<int,int> > g[N];
vector<int> g1[N];
queue<int> q;
void dfs(int u){
tot+=ans[u]; ++res;
minn=min(minn,ans[u]);
for(int i=0; i<g1[u].size(); ++i)
{
int v=g1[u][i];
if(vis[v]) continue;
vis[v]=1;
dfs(v);
}
}
int qread(){
int num=0; char ch=getchar();
while(ch>'9' || ch<'0') ch=getchar();
while(ch<='9' && ch>='0'){
num=num*10+ch-'0';
ch=getchar();
}
return num;
}
int main(){
n=qread(); k=qread();
for(int i=1; i<=n; ++i)
g[0].push_back({i,0});
while(k--){
int opt,x,y;
opt=qread(); x=qread(); y=qread();
g1[x].push_back(y);
g1[y].push_back(x);
if(opt==1){
g[x].push_back({y,0});
g[y].push_back({x,0});
}
if(opt==2) g[y].push_back({x,-1});
if(opt==3) g[x].push_back({y,0});
if(opt==4) g[x].push_back({y,-1});
if(opt==5) g[y].push_back({x,0});
}
memset(ans,0x3f,sizeof(ans));
ans[0]=0; vis[0]=1;
q.push(0);
bool flag=1;
while(!q.empty())
{
int u=q.front(); q.pop(); vis[u]=0;
for(int i=g[u].size()-1; i>=0; --i)
{
int v=g[u][i].first,w=g[u][i].second;
if(ans[u]+w<ans[v]){
ans[v]=ans[u]+w;
if(vis[v]==0){
++cnt[v];
vis[v]=1;
q.push(v);
}
if(cnt[v]>n) {flag=0; break;}
}
}
if(flag==0) break;
}
if(flag)
{
memset(vis,0,sizeof(vis));
for(int i=1; i<=n; ++i){
if(vis[i]==0){
minn=res=0;
vis[i]=1;
dfs(i);
tot=tot-res*minn;
}
}
cout<<tot+n;
}
else
cout<<-1;
return 0;
}