poweroj2883病毒侵染
思路:
寻找割掉
k
k
k条边,使
∏
i
=
1
k
w
i
\prod\limits_{i=1}^{k}w_i
i=1∏kwi最小,我们可以取对数,即求
∑
i
=
1
k
log
w
i
\sum\limits_{i=1}^{k}\log{w_i}
i=1∑klogwi最小,这样就转换成了最小割。但是我们计算答案要寻找割掉的边然后将权值累乘。
可以想到,最小割是指求出权值和最小的边集,使得源点和汇点
S
,
T
S,T
S,T不连通。再考虑到,如果一条边它是割掉的边,那么它的流量一定为
0
0
0(反之不成立)。那么我们可以从
S
S
S出发搜索,如果一条边的
w
i
w_i
wi为
0
0
0,就不继续搜索,用
v
i
s
[
1...
n
]
vis[1...n]
vis[1...n]记录点是否被搜索过。那么我们能够搜索到的点属于一个点集,没有搜索到的点属于另外一个点集,而这两个点集点相互的连边就属于割掉的边。可以用
v
i
s
[
u
]
+
v
i
s
[
v
]
=
=
1
vis[u]+vis[v]==1
vis[u]+vis[v]==1判断。
代码:
#include<bits/stdc++.h>
#define pii pair<int,int>
#define int long long
#define cl(x,y) memset(x,y,sizeof(x))
#define ct cerr<<"Time elapsed:"<<1.0*clock()/CLOCKS_PER_SEC<<"s.\n";
const int N=5e5+210;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const double eps=1e-4;
using namespace std;
struct edge
{
int next,u,v,fl;
double w;
}maze[N<<1];
int len=1,head[N]={0};
int dep[N];//深度
int vis[N]={0};
void add(int u,int v,int fl,double w)
{
maze[++len]={head[u],u,v,fl,w};
head[u]=len;
}
void inc(int u,int v,int w)
{
double k=log(w);
add(u,v,w,k);
add(v,u,w,k);
}
double dfs(int u,double f,int t)
{
double ans=0;
int i;
if(u==t)
return f;
for(i=head[u];i && f;i=maze[i].next)
{
int v=maze[i].v;
double w=maze[i].w;
if(dep[v]==dep[u]+1 && w)//符合深度关系且能流
{
double sum=dfs(v,min(f,w),t);
maze[i].w-=sum;
maze[i^1].w+=sum;
f-=sum;
ans+=sum;
}
}
if(!ans)
dep[u]=-2;
return ans;
}
int bfs(int s,int t)
{
queue<int> q;
cl(dep,0);
dep[s]=1;//源点深度为1
q.push(s);
while(!q.empty())
{
int u=q.front(),i;
q.pop();
for(i=head[u];i;i=maze[i].next)
{
int v=maze[i].v;
double w=maze[i].w;
if(w && !dep[v])//有深度且能流
{
dep[v]=dep[u]+1;
q.push(v);
}
}
}
return dep[t];
}
void dinic(int s,int t)
{
double ans=0;
while(bfs(s,t))
ans+=dfs(s,1e9,t);
}
void find(int u)
{
vis[u]=1;
int i;
for(i=head[u];i;i=maze[i].next)
{
int v=maze[i].v;
double w=maze[i].w;
if(!vis[v] && w)
find(v);
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int n,m;
cin>>n>>m;
int s=1,t=n,i;
for(i=1;i<=m;i++)
{
int u,v,w;
cin>>u>>v>>w;
inc(u,v,w);
}
dinic(s,t);
find(s);
int ans=1,f=0;
for(i=2;i<=len;i+=2)
{
int u=maze[i].u,v=maze[i].v;
if(vis[u]+vis[v]==1)
{
f=1;
ans=ans*maze[i].fl%mod;
}
}
cout<<(f?ans:0)<<endl;
return 0;
}