题解:
真是一道神题!!!
大家还是围观JZP的题解吧(网址找不到了。。。)
代码:
1 #include<cstdio> 2 3 #include<cstdlib> 4 5 #include<cmath> 6 7 #include<cstring> 8 9 #include<algorithm> 10 11 #include<iostream> 12 13 #include<vector> 14 15 #include<map> 16 17 #include<set> 18 19 #include<queue> 20 21 #include<string> 22 23 #define inf 1000000000 24 25 #define maxn 200000+5 26 27 #define maxm 200000+5 28 29 #define eps 1e-10 30 31 #define ll long long 32 33 #define pa pair<int,int> 34 35 #define for0(i,n) for(int i=0;i<=(n);i++) 36 37 #define for1(i,n) for(int i=1;i<=(n);i++) 38 39 #define for2(i,x,y) for(int i=(x);i<=(y);i++) 40 41 #define for3(i,x,y) for(int i=(x);i>=(y);i--) 42 43 #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go) 44 45 #define for5(n,m) for(int i=1;i<=n;i++)for(int j=1;j<=m;j++) 46 47 #define mod 1000000007 48 49 using namespace std; 50 51 inline int read() 52 53 { 54 55 int x=0,f=1;char ch=getchar(); 56 57 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 58 59 while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();} 60 61 return x*f; 62 63 } 64 int n,m,s,t,cut[200][200],a[maxm],b[maxm],c[maxm],maxflow,tot=1,head[maxn],cur[maxn],h[maxn]; 65 66 queue<int>q; 67 bool v[maxn]; 68 69 struct edge{int go,next,v;}e[maxm]; 70 71 inline void add(int x,int y,int v) 72 73 { 74 75 e[++tot]=(edge){y,head[x],v};head[x]=tot; 76 77 e[++tot]=(edge){x,head[y],0};head[y]=tot; 78 79 } 80 81 bool bfs() 82 83 { 84 85 for(int i=1;i<=n;i++)h[i]=-1; 86 87 q.push(s);h[s]=0; 88 89 while(!q.empty()) 90 91 { 92 93 int x=q.front();q.pop(); 94 95 for(int i=head[x];i;i=e[i].next) 96 97 if(e[i].v&&h[e[i].go]==-1) 98 99 { 100 101 h[e[i].go]=h[x]+1;q.push(e[i].go); 102 103 } 104 105 } 106 107 return h[t]!=-1; 108 109 } 110 111 int dfs(int x,int f) 112 113 { 114 115 if(x==t) return f; 116 117 int tmp,used=0; 118 119 for(int i=cur[x];i;i=e[i].next) 120 121 if(e[i].v&&h[e[i].go]==h[x]+1) 122 123 { 124 125 tmp=dfs(e[i].go,min(e[i].v,f-used)); 126 127 e[i].v-=tmp;if(e[i].v)cur[x]=i; 128 129 e[i^1].v+=tmp;used+=tmp; 130 131 if(used==f)return f; 132 133 } 134 135 if(!used) h[x]=-1; 136 137 return used; 138 139 } 140 inline void dfs(int x) 141 { 142 v[x]=1; 143 for4(i,x)if(e[i].v&&!v[y])dfs(y); 144 } 145 146 void dinic() 147 148 { 149 maxflow=0; 150 151 while(bfs()) 152 153 { 154 155 for (int i=1;i<=n;i++)cur[i]=head[i];maxflow+=dfs(s,inf); 156 157 } 158 159 } 160 inline void solve(int l,int r) 161 { 162 if(l==r)return; 163 s=b[l];t=b[r]; 164 for1(i,tot)e[i].v=a[i]; 165 dinic(); 166 for1(i,n)v[i]=0; 167 dfs(s); 168 for1(i,n)if(v[i])for1(j,n)if(!v[j])cut[i][j]=cut[j][i]=min(cut[i][j],maxflow); 169 int t1=l-1,t2=r+1; 170 for2(i,l,r)if(v[b[i]])c[++t1]=b[i];else c[--t2]=b[i]; 171 for2(i,l,r)b[i]=c[i]; 172 solve(l,t1);solve(t2,r); 173 } 174 175 int main() 176 177 { 178 int T=read(); 179 while(T--) 180 { 181 n=read();m=read(); 182 for1(i,n)head[i]=0;tot=1; 183 for1(i,m) 184 { 185 int x=read(),y=read(),w=read(); 186 add(x,y,w);add(y,x,w); 187 } 188 for1(i,tot)a[i]=e[i].v; 189 for1(i,n)b[i]=i; 190 for1(i,n)for1(j,n)cut[i][j]=inf; 191 solve(1,n); 192 int q=read(); 193 while(q--) 194 { 195 int x=read(),ans=0; 196 for1(i,n)for2(j,i+1,n)if(cut[i][j]<=x)ans++; 197 printf("%d ",ans); 198 } 199 printf(" "); 200 } 201 202 return 0; 203 204 }
2229: [Zjoi2011]最小割
Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 685 Solved: 263
[Submit][Status]
Description
小 白在图论课上学到了一个新的概念——最小割,下课后小白在笔记本上写下了如下这段话: “对于一个图,某个对图中结点的划分将图中所有结点分成两个部分,如果结点s,t不在同一个部分中,则称这个划分是关于s,t的割。 对于带权图来说,将所有顶点处在不同部分的边的权值相加所得到的值定义为这个割的容量,而s,t的最小割指的是在关于s,t的割中容量最小的割” 现给定一张无向图,小白有若干个形如“图中有多少对点它们的最小割的容量不超过x呢”的疑问,小蓝虽然很想回答这些问题,但小蓝最近忙着挖木块,于是作为 仍然是小蓝的好友,你又有任务了。
Input
输入文件第一行有 且只有一个正整数T,表示测试数据的组数。 对于每组测试数据, 第一行包含两个整数n,m,表示图的点数和边数。 下面m行,每行3个正整数u,v,c(1<=u,v<=n,0<=c<=106),表示有一条权为c的无向边(u,v) 接下来一行,包含一个整数q,表示询问的个数 下面q行,每行一个整数x,其含义同题目描述。
Output
对于每组测试数据,输出应包括q行,第i行表示第i个问题的答案。对于点对(p,q)和(q,p),只统计一次(见样例)。
两组测试数据之间用空行隔开。
Sample Input
1
5 0
1
0
5 0
1
0
Sample Output
10
【数据范围】
对于100%的数据 T<=10,n<=150,m<=3000,q<=30,x在32位有符号整数类型范围内。
图中两个点之间可能有多条边
【数据范围】
对于100%的数据 T<=10,n<=150,m<=3000,q<=30,x在32位有符号整数类型范围内。
图中两个点之间可能有多条边