11.3清北集訓_獨立集和覆蓋集dpT3
阿新 • • 發佈:2018-11-08
Graph
solution
- 首先把圖用拓撲排序轉換成與之對應的序列
- 發現獨立集就是在序列上的上升子序列
- 發現覆蓋集實際就是任意一個沒有選入子序列的元素都必須與一個在子序列的元素組成逆序對
- 把兩個集結合起來:發現選出的子序列可以把原序列切成若干塊,對於區間(i,j),(i,j)中的所有元素中>=a[i]的min若大於a[j],這個子序列便合法
- 第4點非常重要!!!
- 這樣我們就可以dp了,複雜度O(n^2).
程式碼
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<cmath> #include<cstdlib> #include<ctime> using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const int p=1e9+7; inline int read(){ char ch=' ';int f=1;int x=0; 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; } const int M=1e6; const int N=1e3+100; struct node { int v,nxt; }edge[M]; int head[N],cnt; void add(int u,int v) { cnt++; edge[cnt].v=v; edge[cnt].nxt=head[u]; head[u]=cnt; } int in[N]; priority_queue <int> q;//da int a[N]; int f[N]; int main() { //freopen("graph.in","r",stdin); //freopen("graph.out","w",stdout); int n,m;n=read();m=read(); int i,j; for(i=1;i<=m;i++) { int u=read(),v=read(); if(u>v) swap(u,v); add(u,v);in[v]++; } for(i=1;i<=n;i++) if(!in[i]) q.push(i); for(j=1;j<=n;j++) { int u=q.top();q.pop(); a[u]=n-j+1; for(i=head[u];i;i=edge[i].nxt) { int v=edge[i].v; in[v]--; if(!in[v]) q.push(v); } } // for(i=1;i<=n;i++) // { // cout<<a[i]<<' '; // } // cout<<endl; a[0]=0;a[n+1]=n+1; f[0]=1; for(i=0;i<=n;i++) { int r=n+2; for(j=i+1;j<=n+1;j++) { if(a[j]<a[i]||a[j]>r) continue; f[j]=(f[j]+f[i])%p; r=a[j]; } } printf("%d",f[n+1]); return 0; }