【题目链接】click here~~
【题目大意】:
给定一个无向图,图中的每个结点最初的权值都为0。但每个结点有一次机会,可以增加它本身的权值,但是有个副作用即:在增加自己权值的情况下,也会增加与自己直接相连的结点的权值。 Ignat和Valera打赌说:valera不可能找到一种方法,使得对于每个结点i,它的权值不等于lgnat给定的ai。然后,题目要求写个程序,让valera可以胜,并输出哪个结点要用到,它给定的那次增加的机会。
输入:第1行n,m(1<=n,m<=10^5)分别表示有n个结点,和m条边
第2行到第m+1行每行有两个数u,v,表示结点u,v间有一条边
第m+2行,有n个数表示Ignat 给的ai
输出:若Ignal可以胜,就输出那个有用掉那个机会的结点,否则输出-1
【解题思路】:
CF的题还是比较考思维性的,以后要多刷刷。。
开始还以为是道图论的题,好久没写图论的题了,建边都不会了,后来想了想,可以用队列+容器来写,其实可以发现如果(all)num[i]!=0,即每个counter的权值都不为0 的话,那么之后的操作肯定会改变之后要操作的counter的权值,这种情况是valera的必胜局,那么另一种情况,只要发现num[i]!=0的话,就把它加入队列,输出队列的头部,并且减少与该点相连的所有其他点的权值,与队首相连的元素(比如j)
的权值减1。若它的值为0,则入队。循环操作直到队空。
代码:
#include <bits/stdc++.h> using namespace std; const int N=1e5+5; const int INF=0x3f3f3f3f; vector<int > Edge[N]; vector<int > G; queue<int>vec; int num[N]; int main() { int n,m,u,v,cost; scanf("%d%d",&n,&m); for(int i=0; i<m; i++){ scanf("%d%d",&u,&v); Edge[u].push_back(v); Edge[v].push_back(u); } for(int i=1; i<=n; i++){ scanf("%d",&num[i]); if(num[i]==0) vec.push(i); } while(!vec.empty()) { int head=vec.front(); vec.pop(); G.push_back(head); for(int i=0; i<Edge[head].size(); i++){ int next=Edge[head][i]; num[next]--; if(num[next]==0) vec.push(next); } } printf("%d\n",G.size()); for(int i=0; i<G.size(); i++){ if(G.size()-1==i) printf("%d\n",G[i]); else printf("%d ",G[i]); } return 0; }
时间: 2024-10-14 06:38:02