[luogu4153]k小割
Subtask1(1-2)
暴力枚举割集并检验,时间复杂度为$o(m2^{m})$,可以通过
Subtask2(7-14)
记$a_{i},b_{i}$分别为$s,t$与$i$的边权,则有三种割边方案,代价分别为$a_{i},b_{i}$和$a_{i}+b_{i}$
(不妨假设$a_{i}\le b_{i}$)以$\sum a_{i}$为基础,记$d_{i}=\{b_{i}-a_{i},b_{i}\}$,并将其按$d_{i,0}$从小到大排序
用堆维护三元组$(S,k,p)$,分别表示权值和、当前位置和上一次是否选择$d_{k-1,0}$
初始加入$(0,1,0)$,每次取出堆顶的$(S,k,p)$,并在堆中加入$\begin{cases}(S+d_{k,0},k+1,1)\\(S+d_{k,1},k+1,0)\\(S-d_{k-1,0}+d_{k,0},k+1,1)&p=1\\(S-d_{k-1,0}+d_{k,1},k+1,0)&p=1\end{cases}$
(正确性基于方案生成方式唯一且存在&权值和单调不降,具体显然)
时间复杂度为$o(k\log k)$,可以通过
Subtask3(3-6,15-20)
用堆维护二元组$(E_{1},E_{2})$,表示满足$E_{1}\subseteq C$且$C\cap E_{2}=\empty$的次小割$C$
初始加入$(\empty,\empty)$,每次取出堆顶的$(E_{1},E_{2})$,并在堆中加入$(E_{1}\cup \{i\},E_{2})$和$(E_{1},E_{2}\cup\{i\})$
正确性类似前者,权值和单调性显然,下面考虑方案的生成方式:
1.唯一性,对过程建立二叉树,并对重复的两者分类讨论——
(1)不成祖先后代关系,此时取$lca$处的$i$,两者分别强制$i$在/不在$C$中,则割集必然不同
(2)成祖先后代关系,结合单调性,仅需保证加入的两者均不为$C$即可
记(对应)最小割为$C$,取$i$为$C$和$C_{0}$中状态不同的边,则$C$为最小割/不满足条件,即成立
2.存在性,归纳每个状态能拓展得到除最小割外的所有割集,即显然成立
关于次小割,其相比于最小割仅有两种情况:
1.包含最小割,即额外割掉一条$(割集\cup E_{2})$外的边
2.不包含最小割,枚举去掉的边$(x,y)$,即求$(S,x)$和$(y,T)$在残余网络上的最小割(取$\min$)
时间复杂度为$o(kn\cdot \max Flow(n,m)+k\log k)$,可以通过
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 55 4 #define M 1505 5 #define NN 300005 6 #define ll long long 7 int n,m,K,s,t; 8 struct Edge{int x,y,z;}e[NN]; 9 namespace Subtask1{ 10 int vis[N];vector<int>v0,v[N]; 11 bool check(){ 12 if ((n>10)||(m>20))return 0; 13 for(int i=1;i<=m;i++) 14 if (e[i].z>65536)return 0; 15 return 1; 16 } 17 void dfs(int k){ 18 if (vis[k])return; 19 vis[k]=1; 20 for(int i:v[k])dfs(i); 21 } 22 void main(){ 23 for(int S=0;S<(1<<m);S++){ 24 int sum=0; 25 for(int i=1;i<=n;i++)vis[i]=0,v[i].clear(); 26 for(int i=1;i<=m;i++){ 27 if ((S>>i-1)&1)sum+=e[i].z; 28 else v[e[i].x].push_back(e[i].y); 29 } 30 dfs(s);if (!vis[t])v0.push_back(sum); 31 } 32 sort(v0.begin(),v0.end()); 33 for(int i=0;i<K;i++){ 34 if (i==v0.size()){printf("-1\n");break;} 35 printf("%d\n",v0[i]); 36 } 37 } 38 }; 39 namespace Subtask2{ 40 int a[NN],b[NN];ll sum; 41 pair<int,int>d[NN]; 42 struct Node{ 43 ll S;int k,p; 44 bool operator < (const Node &n)const{ 45 return S>n.S; 46 } 47 }k;priority_queue<Node>q; 48 bool check(){ 49 if (m!=(n<<1)-4)return 0; 50 for(int i=1;i<=m;i++){ 51 if (e[i].x==s)a[e[i].y]=e[i].z; 52 else b[e[i].x]=e[i].z; 53 } 54 for(int i=1;i<=n;i++) 55 if ((i!=s)&&(i!=t)){ 56 if ((!a[i])||(!b[i]))return 0; 57 } 58 return 1; 59 } 60 void main(){ 61 m=0; 62 for(int i=1;i<=n;i++) 63 if ((i!=s)&&(i!=t)){ 64 if (a[i]>b[i])swap(a[i],b[i]); 65 sum+=a[i],d[++m]=make_pair(b[i]-a[i],b[i]); 66 } 67 sort(d+1,d+m+1),q.push(Node{sum,1,0}); 68 for(int i=0;i<K;i++){ 69 if (q.empty()){printf("-1\n");break;} 70 k=q.top(),q.pop(); 71 int j=k.k;printf("%lld\n",k.S); 72 if (j<=m){ 73 int x=d[j].first,y=d[j].second; 74 q.push(Node{k.S+x,j+1,1}),q.push(Node{k.S+y,j+1,0}); 75 if (k.p){ 76 k.S-=d[j-1].first; 77 q.push(Node{k.S+x,j+1,1}),q.push(Node{k.S+y,j+1,0}); 78 } 79 } 80 } 81 } 82 }; 83 namespace Subtask3{ 84 int E,head[N],Head[N],d[N],D[N],visx[N],visy[N];queue<int>q; 85 struct List{int nex,to,len;}edge[M<<1],Edge[M<<1]; 86 void add(int x,int y,int z){ 87 edge[E]=List{head[x],y,z},head[x]=E++; 88 edge[E]=List{head[y],x,0},head[y]=E++; 89 } 90 bool bfs(){ 91 memset(d,-1,sizeof(d)); 92 d[s]=0,q.push(s); 93 while (!q.empty()){ 94 int k=q.front();q.pop(); 95 for(int i=head[k];i!=-1;i=edge[i].nex) 96 if ((edge[i].len)&&(d[edge[i].to]<0)){ 97 d[edge[i].to]=d[k]+1,q.push(edge[i].to); 98 } 99 } 100 return d[t]>=0; 101 } 102 int dfs(int k,int s){ 103 if (k==t)return s; 104 int ans=0; 105 for(int &i=head[k];i!=-1;i=edge[i].nex) 106 if ((edge[i].len)&&(d[edge[i].to]==d[k]+1)){ 107 int p=dfs(edge[i].to,min(s,edge[i].len)); 108 edge[i].len-=p,edge[i^1].len+=p,s-=p,ans+=p; 109 if (!s)return ans; 110 } 111 return ans; 112 } 113 int dinic(int S,int T){ 114 swap(s,S),swap(t,T); 115 int ans=0; 116 while (bfs()){ 117 ans+=dfs(s,1e9); 118 memcpy(head,Head,sizeof(head)); 119 if (ans>=1e9){ans=1e9;break;} 120 } 121 swap(s,S),swap(t,T); 122 return ans; 123 } 124 struct Node{ 125 int S,id;bool E1[M],E2[M]; 126 bool operator < (const Node &n)const{ 127 return S>n.S; 128 } 129 bool calc(){ 130 int mn=1e8;S=0; 131 for(int i=1;i<=m;i++){ 132 edge[(i<<1)-1].len=0; 133 if (E1[i])S+=e[i].z,edge[(i<<1)-2].len=0; 134 else edge[(i<<1)-2].len=(E2[i] ? 1e9 : e[i].z); 135 } 136 S+=dinic(s,t); 137 memcpy(D,d,sizeof(d)); 138 memset(visx,0,sizeof(visx)); 139 memset(visy,0,sizeof(visy)); 140 memcpy(Edge,edge,sizeof(edge)); 141 for(int i=1;i<=m;i++) 142 if ((!E1[i])&&(!E2[i])){ 143 if ((D[e[i].x]<0)||(D[e[i].y]>=0)){ 144 if (e[i].z<mn)mn=e[i].z,id=i; 145 } 146 else{ 147 if (!visx[e[i].x]){ 148 int x=dinic(s,e[i].x); 149 if (x<mn)mn=x,id=i; 150 memcpy(edge,Edge,sizeof(edge)); 151 } 152 if (!visy[e[i].y]){ 153 int y=dinic(e[i].y,t); 154 if (y<mn)mn=y,id=i; 155 memcpy(edge,Edge,sizeof(edge)); 156 } 157 visx[e[i].x]=visy[e[i].y]=1; 158 } 159 } 160 S+=mn; 161 return mn!=1e8; 162 } 163 }k;priority_queue<Node>Q; 164 void add(Node k){ 165 if (k.calc())Q.push(k); 166 } 167 void main(){ 168 memset(head,-1,sizeof(head)); 169 for(int i=1;i<=m;i++)add(e[i].x,e[i].y,e[i].z); 170 memcpy(Head,head,sizeof(head)); 171 K--,printf("%d\n",dinic(s,t)); 172 add(Node{}); 173 for(int i=0;i<K;i++){ 174 if (Q.empty()){printf("-1\n");break;} 175 k=Q.top(),Q.pop(); 176 printf("%d\n",k.S); 177 int x=k.id;k.E1[x]=1,add(k); 178 k.E1[x]=0,k.E2[x]=1,add(k); 179 } 180 } 181 }; 182 int main(){ 183 scanf("%d%d%d%d%d",&n,&m,&s,&t,&K); 184 for(int i=1;i<=m;i++)scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].z); 185 if (Subtask1::check()){ 186 Subtask1::main(); 187 return 0; 188 } 189 if (Subtask2::check()){ 190 Subtask2::main(); 191 return 0; 192 } 193 Subtask3::main(); 194 return 0; 195 }