zju2676 Network Wars 分数规划+网络流

 

题意:给定无向图,每条边有权值,求该图的一个割集,是的该割集的平均边权最小

Amber的《最小割模型在信息学竞赛中的应用》中讲的很清楚了。

二分答案k,对每条边进行重新赋值为原边权-k,求最大流,

可看这里:http://hi.baidu.com/buaa_babt/item/a08fbb45599dc722fb89602a

 二分枚举当前的平均边长l,对于边权<=l的直接加入当前最优割集,边权>l的将容量设为边权-l,加入到网络中,求出最小割的和sum,sum加上刚刚那些小于l的边(也是边权-l),如果大于0就意味着l不可作为最小平均边权,小于0就可以,当等于0时直接输出即可。一定要注意精度

 注意是无向图,还有就是求st割,求解答案。

#define inf 0x3f3f3f3f
#define maxm 100000
#define maxn 10000
#define eps 1e-9
struct node
{
  int u ;
  int v,next,id;
  double w;
  void init(int u1,int v1,double w1)
  {
    u = u1;
    v = v1;
    w = w1;
  }
};
node e1[maxn];
int head[maxn];
int cnt ;
int cnt1;
node edge[maxn];
int sgn(double x) {         //return -1 0 1
  return x < -eps ? -1 : x > eps;
}
void init()
{
  memset(head,-1,sizeof(head));
  cnt = 0 ;
}
void add(int u,int v,int id,double w)
{
  edge[cnt].u = u;
  edge[cnt].v = v;
  edge[cnt].w = w;
  edge[cnt].id = id;
  edge[cnt].next = head[u];
  head[u] = cnt ++ ;

  edge[cnt].u = v;
  edge[cnt].v = u;
  edge[cnt].w = 0;
  edge[cnt].id = id;
  edge[cnt].next = head[v];
  head[v] = cnt ++ ;
}

int dis[maxn];
int pre[maxn],cur[maxn],gap[maxn];
int s,t,nn;

int sap()
{
  double flow,aug;
  int u;
  int flag;
  int i;
  flow=0;
  aug=inf;
  for(i=0; i<nn; i++)
  {
    cur[i]=head[i];
    gap[i]=0;
    dis[i]=0;
  }
  gap[s]=nn;
  u=s;
  pre[s]=s;
  while(dis[s]<nn)
  {
    flag=0;
    for(int &j=cur[u]; j!=-1; j=edge[j].next)
    {
      //cur[u]=j;
      int v=edge[j].v;
      if(edge[j].w>0&&dis[u]==dis[v]+1)
      {
        flag=1;
        if(edge[j].w<aug)aug=edge[j].w;
        pre[v]=u;
        u=v;
        if (u==t)
        {
          flow+=aug;
          while(u!=s)
          {
            u=pre[u];
            edge[cur[u]].w-=aug;
            edge[cur[u]^1].w+=aug;
            //why?解释偶数异或1为偶数+1,奇数异或1为奇数-1,
            //显然我们存的边是从0开始存的,
            //所以偶数,偶数+1是残量网格中的两条边(无向边)
          }
          aug=inf;
        }
        break;
      }
    }
    if (flag) continue;
    int mindis=nn;
    for(int j=head[u]; j!=-1; j=edge[j].next)
    {
      int v=edge[j].v;
      if (edge[j].w>0&&dis[v]<mindis)
      {
        mindis=dis[v];
        cur[u]=j;
      }
    }
    if (--gap[dis[u]]==0)//间隙优化
    {
      break;
    }
    dis[u]=mindis+1;
    gap[dis[u]]++;
    u=pre[u];
  }
  return flow;
}
bool xxx[maxn];
int n,m;
double judge(double lda)
{
  memset(xxx,0,sizeof(xxx));
  init();
  double res = 0.0;
  for(int i = 1; i <= m  ; i ++)
  {
    double tmp ;
    tmp = e1[i].w - lda;
    if( tmp >=0 )
      add(e1[i].u,e1[i].v,i,tmp) , add(e1[i].v,e1[i].u,i,tmp); // 注意
    else
    {
      res += tmp;
      xxx[i] = 1 ;
    }
    //if(sgn(tmp) < 0 )
    //    res += tmp ;
    //else add(e1[i].u,e1[i].v,i,tmp);
  }
  s = 1;
  t = n ;
  nn = t + 2;
  res += sap();
  return res;
}
queue<int> q;
int col[maxn];
bool vis[maxn];
void bfs(int st,int color)
{
  memset(vis,0,sizeof(vis));
  memset(col,0,sizeof(col));
  while(!q.empty()) q.pop();
  q.push(st);
  vis[st] = 1;
  col[st] = color;
  while(!q.empty())
  {
    int u = q.front();
    q.pop();
    for(int i = head[u] ; i != -1; i = edge[i].next)
    {
      int v = edge[i].v;
      if(sgn(edge[i].w) > 0 && vis[v] == 0 )
      {
        vis[v] = 1;
        col[v] = color;
        q.push(v);
      }
    }
  }
  return ;
}
vector<int> ans ;
void getst(double lda)
{
  bfs(1,1);
  ans.clear();
  for(int i = 1 ; i <= m ; i ++ )     // 注意 
  {
    if(!xxx[i])
    {
      if(col[e1[i].u] != col[e1[i].v] )
      {
        ans.push_back(i);
      }
    }
    else ans.push_back(i);
  }
  int size = ans.size();
  sort(ans.begin(),ans.end());
  printf("%d\n",size);
  for(int i = 0; i < size ; i++ )
  {
    printf("%d",ans[i]);
    if(i != size - 1 ) printf(" ");
    else printf("\n");
  }
}
int main()
{
  int cas;
  cas = 0 ;
  while(scanf("%d%d",&n,&m)!=EOF)
  {
    cnt1 = 1 ;
    int u,v;
    double w;
    double L,R;
    L = eps;
    for(int i = 1 ; i <= m; i ++ )
    {
      scanf("%d%d%lf",&u,&v,&w);
      e1[i].init(u,v,w);
      R = max(R , w);
    }
    double mid ;
    for(int i = 0 ; i < 101 ; i ++ )
      // while( R - L > eps )
    {
      mid = ( L + R ) / 2.0;
      double tmp = judge(mid);
      if(sgn(tmp ) > 0 )    // 判断
        L = mid + eps;
      else R = mid;
    }
    if(cas != 0 ) printf("\n");
    cas ++ ;
    judge(L);
    getst(L);
  }
  return 0;
}    
View Code

 

posted on 2013-08-29 20:36  oshixiaoxiliu  阅读(440)  评论(0编辑  收藏  举报

导航