[补档][Usaco2015 Jan]Grass Cownoisseur
[Usaco2015 Jan]Grass Cownoisseur
题目
给一个有向图,然后选一条路径起点终点都为1的路径出来,有一次机会可以沿某条边逆方向走,问最多有多少个点可以被经过?(一个点在路径中无论出现多少正整数次对答案的贡献均为1)INPUT
The first line of input contains N and M, giving the number of fields and the number of one-way paths (1 <= N, M <= 100,000). The following M lines each describe a one-way cow path. Each line contains two distinct field numbers X and Y, corresponding to a cow path from X to Y. The same cow path will never appear more than once.N个点,M条有向边,无重边OUTPUT
A single line indicating the maximum number of distinct fields Bessiecan visit along a route starting and ending at field 1, given that she canfollow at most one path along this route in the wrong direction.SAMPLE
INPUT
7 101 23 12 52 43 73 53 66 57 24 7OUTPUT
6
解题报告
这道题考试的时候,一看就知道是tarjan,然后就真的傻傻的打了个tarjan+dfs,就A了一个点= =
正解:
tarjan缩点,因为可以逆转一条边,而同一强连通分量里的边逆转是没啥用的,所以我们可以枚举缩点后的边。
首先,跑2遍SPFA,一遍缩点后的正边,一遍反边,处理出正反两个最大的经过权值(每点权值为缩点后强连通分量的点数)。
剩下的就很简单了,思考当一条有向边反过来时,它反边的起点走的是正向的最大权值,而终点则走的是反向的最大权值,那么我们枚举每一条边,两权相加求max即为答案。
注意:特判,两边SPFA若有一遍没有联通这条边对应的强连通分量,这个点就不能跑。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<queue> 5 using namespace std; 6 inline int read(){ 7 int sum(0); 8 char ch(getchar()); 9 while(ch<'0'||ch>'9') 10 ch=getchar(); 11 while(ch>='0'&&ch<='9'){ 12 sum=sum*10+ch-'0'; 13 ch=getchar(); 14 } 15 return sum; 16 } 17 struct edge{ 18 int s,e,n; 19 }k[100001],a[100001],b[100001]; 20 int pre[100001],tot; 21 inline void insert(int s,int e){ 22 k[++tot].s=s; 23 k[tot].e=e; 24 k[tot].n=pre[s]; 25 pre[s]=tot; 26 } 27 int low[100001],dfn[100001],stack[100001],bl[100001],size[100001]; 28 int head,cnt,qlt; 29 bool vis[100001]; 30 inline int my_min(int a,int b){ 31 return a<b?a:b; 32 } 33 inline int my_max(int a,int b){ 34 return a>b?a:b; 35 } 36 inline void tarjan(int u){ 37 low[u]=dfn[u]=++cnt; 38 vis[u]=1; 39 stack[++head]=u; 40 for(int i=pre[u];i!=-1;i=k[i].n){ 41 int e(k[i].e); 42 if(!dfn[e]){ 43 tarjan(e); 44 low[u]=my_min(low[u],low[e]); 45 } 46 else 47 if(vis[e]) 48 low[u]=my_min(low[u],dfn[e]); 49 } 50 if(low[u]==dfn[u]){ 51 int tmp; 52 qlt++; 53 while(1){ 54 tmp=stack[head--]; 55 bl[tmp]=qlt; 56 vis[tmp]=0; 57 if(tmp==u) 58 break; 59 } 60 } 61 } 62 int adj[100001],num; 63 inline void add(int s,int e){ 64 a[++num].s=s; 65 a[num].e=e; 66 a[num].n=adj[s]; 67 adj[s]=num; 68 } 69 queue<int>q; 70 int fz[100001]; 71 inline void spfa1(int x){ 72 memset(vis,0,sizeof(vis)); 73 memset(fz,0,sizeof(fz)); 74 q.push(x); 75 fz[x]=size[x]; 76 vis[x]=1; 77 while(!q.empty()){ 78 int k(q.front()); 79 q.pop(); 80 for(int i=adj[k];i!=-1;i=a[i].n){ 81 int e(a[i].e); 82 if(fz[e]<fz[k]+size[e]){ 83 fz[e]=fz[k]+size[e]; 84 if(!vis[e]){ 85 q.push(e); 86 vis[e]=1; 87 } 88 } 89 } 90 vis[k]=0; 91 } 92 } 93 int hhh,nxt[100001]; 94 inline void init(int s,int e){ 95 b[++hhh].s=s; 96 b[hhh].e=e; 97 b[hhh].n=nxt[s]; 98 nxt[s]=hhh; 99 } 100 int ff[100001]; 101 inline void spfa2(int x){ 102 memset(vis,0,sizeof(vis)); 103 memset(ff,0,sizeof(ff)); 104 q.push(x); 105 ff[x]=size[x]; 106 vis[x]=1; 107 while(!q.empty()){ 108 int k(q.front()); 109 q.pop(); 110 for(int i=nxt[k];i!=-1;i=b[i].n){ 111 int e(b[i].e); 112 if(ff[e]<ff[k]+size[e]){ 113 ff[e]=ff[k]+size[e]; 114 if(!vis[e]){ 115 q.push(e); 116 vis[e]=1; 117 } 118 } 119 } 120 vis[k]=0; 121 } 122 } 123 inline int find(int x){ 124 int s(a[x].e),e(a[x].s); 125 if(!fz[s]||!ff[e]) 126 return 0; 127 return fz[s]+ff[e]-size[bl[1]]; 128 } 129 int n,m; 130 int main(){ 131 memset(pre,-1,sizeof(pre)); 132 memset(adj,-1,sizeof(adj)); 133 memset(nxt,-1,sizeof(nxt)); 134 n=read(),m=read(); 135 for(int i=1;i<=m;i++){ 136 int x(read()),y(read()); 137 insert(x,y); 138 } 139 for(int i=1;i<=n;i++) 140 if(!dfn[i]) 141 tarjan(i); 142 for(int i=1;i<=n;i++) 143 size[bl[i]]++; 144 for(int i=1;i<=tot;i++){ 145 int s(k[i].s),e(k[i].e); 146 if(bl[s]!=bl[e]) 147 add(bl[s],bl[e]),init(bl[e],bl[s]); 148 } 149 spfa1(bl[1]); 150 spfa2(bl[1]); 151 int ans(0); 152 for(int i=1;i<=num;i++) 153 ans=my_max(ans,find(i)); 154 printf("%d\n",ans); 155 }
ps:调了我两个小时,最后发现重新建边的时候我用的原来点的编号,没有用缩完点后的编号,然后就听取蛙声一片了= =