题意:给定一个有向图,从一个节点出发到所有的节点需要翻转多少次方向,问最小翻转次数为多少次
条件:1 如果是无向图,这整个图都是通的
2 题目给出的n节点的个数是2·10^5
思路:题目给出的n节点的个数是2·10^5,所以存地图的时候要用vector,而且绝对不能暴力。想必肯定只用遍历一次就可以得到其它点的关系,以此想法为突破口,就会发现我任选一个起始点,只要遍历起始点到其他所有的顶点的到翻转次数和起始点到该个点需要的翻转和不翻转次数。其它点的到其它所有点翻转次数=起始点到其他所有的顶点的到翻转次数-起始点到该个点需要的翻转次数+起始点到该个点需要的不翻转次数。(ans[i]=count1-vis[i][1]+vis[i][3])
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <cstring>
using namespace std;
const int maxn=200005;
int count1;//总逆置步数
vector<int>num[maxn*2];//地图
int vis[maxn][4];//记录有没有办拜访过,起始点到该店翻转数和不翻转数
int ans[maxn];//统计每一个节点翻转数
int main()
{
int n;
scanf("%d",&n);
memset(vis,0,sizeof(vis));
count1=0;
for(int i=0;i<n-1;i++)
{
int x,y;
scanf("%d%d",&x,&y);
num[x].push_back(y);
num[y+n].push_back(x);
}
vis[1][0]=1;//有没有来过
vis[1][1]=0;//从选定起点到这里逆置数
//原先这里有vis[1][2]但其实2不起作用的,所以没有必要
vis[1][3]=0;//不逆置数目
stack<int>s;
s.push(1);
int numcount=1;
while(numcount<n)//遍历
{
int i;
i=s.top();
s.pop();
for(int j=0;j<num[i].size();j++)
{
int x=num[i][j];
if(vis[x][0]==1)//如果已经访问过
continue;
vis[x][0]=1;
vis[x][1]=vis[i][1];
vis[x][3]=vis[i][3]+1;
s.push(x);
numcount++;
}
for(int j=0;j<num[i+n].size();j++)
{
int x=num[i+n][j];
if(vis[x][0]==1)
continue;
vis[x][0]=1;
vis[x][1]=vis[i][1]+1;
vis[x][3]=vis[i][3];
count1++;
s.push(x);
numcount++;
}
}
int min1=count1;
ans[1]=count1;
for(int i=1;i<=n;i++)
{
ans[i]=count1-vis[i][1]+vis[i][3];
min1=min(ans[i],min1);
}
printf("%d\n",min1);
for(int i=1;i<=n;i++)
{
if(ans[i]==min1)
printf("%d ",i);
}
return 0;
}
总结:1 那次题目做的还是不错,挺多人没做出来,想法真的挺重要的,但也需要平时多多积累
2 看了队里大家补题的记录,别人都那么努力,凭什么自己不加把劲