标签:
这是一道坑题,测试数据有误,标算有误,所以想要AC需要和标算错的一样 详见Discuss
询问了AC此题的Claris,得到的回复是:
说说正确做法:
仍旧是仙人掌DP,这里的话是仙人掌森林,不过原理是一样的e
求解最大点权独立集,然后仔细读样例发现,这里的“独立集”不同于平常的独立集,即不能选中间隔着一个的两个点
那么对于正常的求解方法是dp[i][0/1]表示当前到i位,选或不选的答案,这里就带限制的dp[i][0/1/2]去进行dp即可,转移是类似的
对仙人掌的处理方法一样是找环,拆环单独DP
这里提供自己的正确做法(WA3组(数据有误)AC其余)
除discuss中提及的3组全A,并与提及的3组的正确答案相吻合
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; int read() { int x=0,f=1; char ch=getchar(); while (ch<‘0‘ || ch>‘9‘) {if (ch==‘-‘) f=-1; ch=getchar();} while (ch>=‘0‘ && ch<=‘9‘) {x=x*10+ch-‘0‘; ch=getchar();} return x*f; } #define maxn 1000100 struct EdgeNode{int to,next;}edge[maxn<<2]; int head[maxn],cnt; void add(int u,int v) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v;} void insert(int u,int v) {add(u,v); add(v,u);} int deep[maxn],fa[maxn],dfn[maxn],low[maxn],dp1[maxn][3],dp2[maxn][3],ring[maxn],HX[maxn],t; int n,m,ans; void CactusDP(int st,int tt) { ring[1]=tt; int zz=1; while (ring[zz]!=st) {ring[zz+1]=fa[ring[zz]]; zz++;} //printf("Num=%d :",zz); //for (int i=1; i<=zz; i++) printf("%d ->",ring[i]); printf("\n"); int f0=0,f1=0,f2=0; for (int opt=0; opt<=2; opt++) { dp2[1][0]=dp2[1][1]=dp2[1][2]=0; dp2[1][opt]=dp1[tt][opt]; if (opt==2) dp2[1][1]=dp2[1][2]; for (int i=2; i<=zz; i++) dp2[i][0]=dp2[i-1][2]+dp1[ring[i]][0], dp2[i][1]=max(max(dp2[i-1][1],dp2[i-1][0])+dp1[ring[i]][2],dp2[i-1][1]+dp1[ring[i]][1]), dp2[i][2]=max(dp2[i-1][1],dp2[i-1][2])+dp1[ring[i]][2]; if (opt==0) f1=max(f1,dp2[zz][2]); if (opt==1) f1=max(f1,dp2[zz][1]),f2=max(f2,dp2[zz][2]); if (opt==2) f1=max(f1,dp2[zz][1]),f0=max(f0,dp2[zz][0]),f2=max(f2,dp2[zz][2]); } dp1[st][0]=f0; dp1[st][1]=f1; dp1[st][2]=f2; } void TreeDP(int now) { dfn[now]=low[now]=++t; dp1[now][2]=0; dp1[now][0]=HX[now]; int maxx=0; for (int i=head[now]; i; i=edge[i].next) if (edge[i].to!=fa[now]) { if (deep[edge[i].to]) {low[now]=min(dfn[edge[i].to],low[now]); continue;} fa[edge[i].to]=now; deep[edge[i].to]=deep[now]+1; TreeDP(edge[i].to); if (low[edge[i].to]>low[now]) dp1[now][2]+=max(dp1[edge[i].to][1],dp1[edge[i].to][2]), dp1[now][0]+=dp1[edge[i].to][2], maxx=max(maxx,dp1[edge[i].to][0]-max(dp1[edge[i].to][1],dp1[edge[i].to][2])); low[now]=min(low[now],low[edge[i].to]); } dp1[now][1]=maxx+dp1[now][2]; for (int i=head[now]; i; i=edge[i].next) if (low[edge[i].to]==dfn[now] && edge[i].to!=fa[now] && deep[edge[i].to]!=deep[now]+1) CactusDP(now,edge[i].to); } void Freopen() {freopen("area.in","r",stdin); freopen("area.out","w",stdout);} void Fclose() {fclose(stdin); fclose(stdout);} int main() { //Freopen(); n=read(),m=read(); for (int i=1; i<=n; i++) HX[i]=read(); for (int u,v,i=1; i<=m; i++) u=read(),v=read(),insert(u,v); for (int i=1; i<=n; i++) if (!dfn[i]) {fa[i]=i,deep[i]=1; TreeDP(i); ans+=max(dp1[i][0],max(dp1[i][1],dp1[i][2]));} printf("%d\n",ans); //Fclose(); return 0; }
以及可A的标程,显然标程的判环是有些问题的
开荒做这种大坑,简直了= =||
【BZOJ-1952】Area [坑题] 仙人掌DP + 最大点权独立集(改)
标签:
原文地址:http://www.cnblogs.com/DaD3zZ-Beyonder/p/5596732.html