[BZOJ 3373] Lying Livestock 说谎的牲畜
·题目描述
兽群中总是有一些麻烦制造者.约翰知道他的N(1≤N≤100)头奶牛中有一头总是说谎,其他的总是说真话.他想快速的找出这个麻烦制造者.为了实现这个目标,他一个一个的问这些奶牛Q(1≤Q≤1000)个关于它们吃草的简单问题(虽然大多数奶牛是诚实的但它们依旧很笨只能懂得一些关于食物的话题).
他将这些问题用以下的格式写了下来:
牛4说:牛5比牛10吃得多
牛6说:牛10比牛7吃得多
牛3说:牛2比牛6吃得多
牛1说:牛7比牛5吃得多
从这个例子中不难看出说谎的奶牛只有可能是4,6,1.你的任务是确定可能说谎的奶牛的个
数.可能说谎的奶牛是指如果这头奶牛说谎则输入数据中不存在矛盾.
·输入格式
第1行:两个用空格分开的整数N和Q.第2到Q+1:每一行描述一个问题,由3个用空格隔开的整数A,B,C表示,意思是A说B牛吃的比C牛多.一头奶牛可能回答多次.
·输出格式
仅一行一个整数即可能说谎的奶牛的头数.
·样例输入
3 4
3 1 2
1 3 1
1 3 2
2 2 1
·样例输出
2
题解:
什么都别说了,很裸的差分约束;枚举说谎的牛,然后再建图,跑SPFAε=ε=ε=(~ ̄▽ ̄)~,就完了。
详情请见代码↓↓↓
#include <queue> #include <stdio.h> #include <string.h> #include <iostream> using namespace std; struct info{ int u[105],v[105],sum; }data[105]; struct Edge{ int to,next,w; }edge[1005]; queue <int> q; int i,A,B,C,cnt,head[105]; int N,Q,dis[105],vis[105],s[105],ans; void AddEdge(int u,int v,int w) { edge[++cnt].to=v; edge[cnt].next=head[u]; edge[cnt].w=w; head[u]=cnt; } void BuildGragh(int k) { cnt=0; memset(head,0,sizeof(head)); for (int i=1; i<=N; ++i) AddEdge(0,i,0); for (int p=1; p<=N; ++p) for (int i=1; i<=data[p].sum; ++i) if (p!=k) AddEdge(data[p].u[i],data[p].v[i],-1); else AddEdge(data[p].v[i],data[p].u[i],0); } bool SPFA() { while (!q.empty()) q.pop(); memset(dis,127/2,sizeof(dis)); memset(vis,0,sizeof(vis)); memset(s,0,sizeof(s)); dis[0]=0; vis[0]=s[0]=1; q.push(0); while (!q.empty()) { int now=q.front(); q.pop(); vis[now]=0; for (int i=head[now];i;i=edge[i].next) if (dis[edge[i].to]>dis[now]+edge[i].w) { dis[edge[i].to]=dis[now]+edge[i].w; if (!vis[edge[i].to]) { vis[edge[i].to]=1; ++s[edge[i].to]; if (s[edge[i].to]>N) return false; q.push(edge[i].to); } } } return true; } int main(int argc, char const *argv[]) { scanf("%d%d",&N,&Q); for (i=1; i<=Q; ++i) { scanf("%d%d%d",&A,&B,&C); ++data[A].sum; data[A].u[data[A].sum]=B; data[A].v[data[A].sum]=C; } for (i=1; i<=N; ++i) { BuildGragh(i); if (SPFA()) ans++; } printf("%d\n",ans); return 0; }