• HZOJ 回家


    这篇博客大部分在写我的错解……明明很简单的一道题,知道正解后10分钟AC,然而几个错解打的想死……

    错解1 WA40:

    鬼知道这40分哪来的……这也是考试最后很无奈地交上去的代码,最后剩20分钟时发现这是错的,最后剩7分钟想出错解2,我也是醉了……

    先说一下思路吧,首先跑一边Dijkstra记录1到n的最短路,那么必经点一定在这条路径上。然后怎么搞呢?以下纯属YY,从n开始向回扫,遇到第一个dis不是INF的停止……鬼知道我咋想的,其实是为了QJ样例

    1 tem=n;
    2 while(tem!=1)
    3 {
    4     if(tem!=n)ans.push_back(tem);
    5     if(dis[tem]!=INF)break;
    6     nex[u(pre[tem])]=tem;
    7     tem=u(pre[tem]);
    8 }
    代码片段

    错解2 WA90:

    只能说测试点有点水啊,接着上面说,找到了最短路,必经点在这条路径上,但是这条路径上的点不一定都是必经点,什么情况下点i不是毕竟点呢?我们可以发现,当i被一条其他边覆盖时,i一定不是必经点,这里的覆盖不包括连接:如图节点3就被覆盖,而节点2,4就不算被覆盖,知道了这个结论,我们就可以求出来答案了,具体怎么做呢?首先tarjan缩边双,记录每个边双在这条路径上的端点,那么我们就可一求出答案了。但是难点就在于边双的端点记录起来比较难以实现。以上是正确结论,以下纯属YY:

    可以发现端点一定是和桥连着的,所以我们连索点都省了,只需要记录这条路径,然后tarjan求割边,枚举边,将即在这条路径上又是桥的边的端点(1,n除外)扔入vector,最后排序去重即可。

    显然以上YY是错的(其实可能并不显然),直接上数据好了:

    如图,显然4是必经点,但是4没有与割边连接,只能说测试点太水了,居然有90分……

      1 #include<algorithm>
      2 #include<iostream>
      3 #include<cstring>
      4 #include<cstdio>
      5 #include<queue>
      6 #define int long long
      7 #define MAXN 2000010
      8 #define MP(a,b) make_pair(a,b)
      9 #define ma(x) memset(x,0,sizeof(x))
     10 #define min(a,b) ((a)<(b)?(a):(b))
     11 using namespace std;
     12 const int L=1<<20|1;
     13 char buffer[L],*S,*T;
     14 #define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,L,stdin),S==T))?EOF:*S++)
     15 struct edge
     16 {
     17     int u,v,nxt;
     18     #define u(x) ed[x].u    
     19     #define v(x) ed[x].v
     20     #define n(x) ed[x].nxt
     21 }ed[MAXN*2];
     22 int first[MAXN],num_e=1;
     23 #define f(x) first[x]
     24 int TT,n,m;
     25 int dfn[MAXN],low[MAXN],cnt;
     26 bool bridge[MAXN*2];
     27 void tarjan(int x,int edg,int fa)
     28 {    
     29     dfn[x]=low[x]=++cnt;
     30     for(int i=f(x);i;i=n(i))
     31     if(!dfn[v(i)])
     32     {    
     33         tarjan(v(i),i,x),low[x]=min(low[x],low[v(i)]);
     34         if(low[v(i)]>dfn[x])
     35             bridge[i]=bridge[i^1]=1;
     36     }
     37     else if(v(i)!=fa&&(i^1)!=edg)low[x]=min(low[x],dfn[v(i)]);
     38 }
     39 int dis[MAXN];bool v[MAXN];
     40 int pre2[MAXN];
     41 void dist2(int st)
     42 {
     43     for(int i=0;i<=n;i++)dis[i]=0x7ffffffffff,v[i]=0;
     44     dis[st]=0;
     45     priority_queue<pair<int,int> >q;
     46     q.push(MP(0,st));
     47     while(!q.empty())
     48     {
     49         int x=q.top().second;q.pop();
     50         if(v[x])continue;v[x]=1;
     51         for(int i=f(x);i;i=n(i))
     52         if(dis[v(i)]>dis[x]+1)
     53         {    
     54             dis[v(i)]=dis[x]+1;    
     55             pre2[v(i)]=i;
     56             q.push(MP(-dis[v(i)],v(i)));
     57         }
     58     }
     59 }
     60 bool is[MAXN*2];
     61 int ans[MAXN*4],an;
     62 inline void add(int u,int v);
     63 inline int read()
     64 {
     65     int s=0;char a=getchar();
     66     while(a<'0'||a>'9')a=getchar();
     67     while(a>='0'&&a<='9'){s=s*10+a-'0';a=getchar();}
     68     return s;
     69 }
     70 signed main()
     71 {
     72 //    freopen("in.txt","r",stdin);    
     73 //    freopen("0.out","w",stdout);
     74 
     75     cin>>TT;
     76     while(TT--)    
     77     {
     78     
     79         cnt=0;num_e=1;ma(ans),an=0;
     80         n=read(),m=read();
     81         for(int i=0;i<=n;i++)first[i]=is[i]=pre2[i]=low[i]=dfn[i]=0;
     82         ma(bridge);ma(is);
     83         int ta,tb;
     84         for(int i=1;i<=m;i++)
     85         {
     86             ta=read(),tb=read();
     87             add(ta,tb),add(tb,ta);
     88         }
     89         dist2(1);
     90         int tem=n;
     91         while(tem!=1)
     92         {    
     93             is[pre2[tem]]=is[pre2[tem]^1]=1;
     94             tem=u(pre2[tem]);
     95         }
     96         for(int i=1;i<=n;i++)
     97         if(!dfn[i])tarjan(i,0,0);
     98         for(int i=2;i<=num_e;i+=2)
     99         if(bridge[i]&&is[i])
    100         {    
    101             if(u(i)!=1&&u(i)!=n)ans[++an]=u(i);
    102             if(v(i)!=1&&v(i)!=n)ans[++an]=v(i);
    103         }
    104         sort(ans+1,ans+an+1);
    105         int m=unique(ans+1,ans+an+1)-ans-1;
    106         printf("%lld
    ",m);
    107         for(int i=1;i<=m;i++)
    108             printf("%lld ",ans[i]);
    109         printf("
    ");
    110     }
    111 }
    112 inline void add(int u,int v)
    113 {
    114     ++num_e;
    115     u(num_e)=u;
    116     v(num_e)=v;
    117     n(num_e)=f(u);
    118     f(u)=num_e;
    119 }
    错解代码也放一下吧

    正解:

    以上纯属扯淡,其实这个题还是求割点,只要在tarjan是加一句特判就可以了,几乎就是裸的tarjan……

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #define ma(x) memset(x,0,sizeof(x))
    #define MAXN 2000010
    using namespace std;
    struct edge
    {
    	int u,v,nxt;	
    	#define u(x) ed[x].u
    	#define v(x) ed[x].v
    	#define n(x) ed[x].nxt
    }ed[MAXN*2];
    int first[MAXN],num_e;
    #define f(x) first[x]
    
    int n,m;
    int dfn[MAXN],low[MAXN],num,root;
    bool cut[MAXN];
    int stack[MAXN],top;
    void tarjan(int x)
    {
    	dfn[x]=low[x]=++num;
    	stack[++top]=x;
    	if(x==root&&!f(x)){return;}
    	int flag=0;
    	for(int i=f(x);i;i=n(i))
    	if(!dfn[v(i)])
    	{
    		tarjan(v(i)),low[x]=min(low[x],low[v(i)]);
    		if(low[v(i)]>=dfn[x]&&dfn[v(i)]<=dfn[n]&&dfn[n])//x是割点,如果dfn[v(i)]<=dfn[n]则说明如果要到n必须经过x。
    		{
    			flag++;
    			if(x!=root||flag>1)	cut[x]=1;
    		}
    	}
    	else low[x]=min(low[x],dfn[v(i)]);
    }
    int TT;
    inline int read()
    {
    	int s=0;char a=getchar();
    	while(a<'0'||a>'9')a=getchar();
    	while(a>='0'&&a<='9'){s=s*10+a-'0';a=getchar();}
    	return s;
    }
    inline void add(int u,int v)
    {
    	++num_e;
    	u(num_e)=u;
    	v(num_e)=v;
    	n(num_e)=f(u);
    	f(u)=num_e;
    }
    signed main()
    {
    	cin>>TT;
    	while(TT--)	
    	{
    		ma(first);ma(cut);num=root=top=0;ma(ed);ma(dfn);ma(low);
    		n=read(),m=read();
    		int ta,tb;
    		for(int i=1;i<=m;i++)
    		{
    			ta=read(),tb=read();
    			add(ta,tb),add(tb,ta);
    		}
    		for(int i=1;i<=n;i++)
    		if(!dfn[i])root=i,tarjan(i);
    		int nn=0;
    		for(int i=2;i<n;i++)
    		if(cut[i])nn++;
    		printf("%d
    ",nn);
    		for(int i=2;i<n;i++)
    		if(cut[i])printf("%d ",i);
    		puts("");
    	}
    }
    
  • 相关阅读:
    20210304
    20210303
    20210302
    20210210
    20210209
    20210208
    20210207
    例4-6
    例4-5
    例4-4
  • 原文地址:https://www.cnblogs.com/Al-Ca/p/11247990.html
Copyright © 2020-2023  润新知