大致题义:

给出n条鱼之间相互攻击的关系以及每条鱼的能量值,每条鱼只能攻击或者被攻击最多一次(也就是被攻击之后无法攻击别人,或者攻击别人之后无法被攻击)。一次攻击行为产能为这两条鱼能量值的异或值。求总能量值最大是多少。

大致思路:

用KM算法,把每条鱼拆做两个点,连别求最大匹配的思路很容易想到,代码如下。

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int nMax=204;
const int mMax=1005;
const int inf=1<<29;
int map[nMax][nMax];
int lx[nMax],ly[nMax];
int mapch[nMax];
int stack[nMax];
bool sy[nMax],sx[nMax];
int n,m,e,cnt;
int find (int u){int v,t;sx[u]=1;for(v=1;v<=m;v++){if(sy[v]) continue;t=lx[u]+ly[v]-map[u][v];if(t==0){sy[v]=1;if(mapch[v]==-1||find(mapch[v])){mapch[v]=u;return 1;}}else if(t<stack[v]) stack[v]=t;}return 0;
}
int KM(){int i,j,k,d,sum=0;cnt=0;for(i=1;i<=m;i++)ly[i]=0;memset(mapch,-1,sizeof(mapch));for(i=1;i<=n;i++){lx[i]=-inf;for(j=1;j<=m;j++)if(map[i][j]>lx[i])lx[i]=map[i][j];}for(i=1;i<=n;i++){for(j=1;j<=m;j++)stack[j]=inf;while(1){for(k=1;k<=m;k++) sy[k]=0;for(k=1;k<=n;k++) sx[k]=0;if(find(i)) break;d=inf;for(k=1;k<=m;k++)if(!sy[k]&&stack[k]<d)d=stack[k];for(k=1;k<=n;k++)if(sx[k]) lx[k]-=d;for(k=1;k<=m;k++)if(sy[k]) ly[k]+=d;else stack[k]-=d;}}for(i=1;i<=m;i++)if(mapch[i]!=-1&&map[mapch[i]][i]!=-inf){sum+=map[mapch[i]][i];}return sum;
}char str[nMax];
int val[nMax];
int main(){int i,j,a;while(scanf("%d",&n)&&n){m=n;memset(map,0,sizeof(map));for(i=1;i<=n;i++)scanf("%d",&val[i]);for(i=1;i<=n;i++){scanf("%s",str+1);for(j=1;j<=n;j++){if(str[j]=='1'){map[i][j]=val[i]^val[j];}}}printf("%d\n",KM());}return 0;
}

起初我用的是费用流,但是却wa了。连边构图时我很容易就能联想到,对每条鱼a,我们都将其拆做两点a和a‘。从原点向a连边,容量是1,费用是0。从a’向汇点连边,容量是1,费用是0。如果a攻击b则连接a->b'容量为1,费用为这两条鱼能产生的产能。求出费用流即可。但是却wa了……囧。后来看了 AekdyCoin 才明白。因为求出费用流的时候,流量必须是最大 。也就是这道题中得到最大产能的时候,图中的流量未必是最大。如下图


 我们希望的答案是9,但是费用流得到的结果是2!因为当费用是9的时候,当前网络还未达到最大流。

为了解决以上问题,对于每个a,我们可以连接一条边a->t,使得总流量等于鱼的数量。接下来求出最小费用即可。

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int inf=99999999;
const int nMax=3000;
const int mMax=2000000;
struct{int u,v, cap, cost, next, re;
}edge[mMax];
int ans,maxf;
int k,edgeHead[nMax];
int que[nMax],pre[nMax],dis[nMax];
bool vis[nMax],flag;
int K;
void addEdge(int u,int v,int ca,int co){始点 终点 流量 花费edge[k].v=v;edge[k].cap=ca;edge[k].cost=co;edge[k].next=edgeHead[u];edge[k].re=k + 1;edgeHead[u]=k ++;edge[k].v=u;edge[k].cap=0;edge[k].cost=-co;edge[k].next=edgeHead[v];edge[k].re=k - 1;edgeHead[v]=k ++;
}bool spfa(int s,int t,int n){      //始点,终点,总点数int i, head = 0, tail = 1;    //  长注释的地方就是从最小费用改到最大费用时需要变动的地方for(i = 0; i <= n; i ++){dis[i] = -inf;vis[i] = false;}dis[s] = 0;que[0] = s;vis[s] = true;while(head != tail){int u = que[head];for(i = edgeHead[u]; i != 0; i = edge[i].next){int v = edge[i].v;if(edge[i].cap && dis[v] <dis[u] + edge[i].cost){dis[v] = dis[u] + edge[i].cost;pre[v] = i;if(!vis[v]){vis[v] = true;que[tail ++] = v;if(tail == nMax) tail = 0;}}}vis[u] = false;head++;if(head ==nMax) head = 0;}if(dis[t] ==-inf) return false;///return true;
}void end(int s,int t){int u, p;for(u = t;u!=s;u=edge[edge[p].re].v){p = pre[u];edge[p].cap-=1;edge[edge[p].re].cap+=1;ans+=edge[p].cost;}maxf+=1;   //总流量
}int num[nMax];
char xxx[105][105];
int main(){int n,m,i,j,s,t,a,b,c;while(scanf("%d",&n)!=EOF&&n){k=1;ans=maxf=0;s=0,t=2*n+1;memset(edgeHead,0,sizeof(edgeHead));for(i=1;i<=n;i++){scanf("%d",&num[i]);}for(i=1;i<=n;i++){scanf("%s",xxx[i]+1);}for(i=1;i<=n;i++){addEdge(s,i,1,0);addEdge(i,t,1,0);  /!!!!!!!addEdge(i+n,t,1,0);}for(i=1;i<=n;i++){for(j=1;j<=n;j++){if(xxx[i][j]=='1'){a=num[i]^num[j];addEdge(i,j+n,1,a);}}}while(spfa(s,t,2*n+2)){end(s,t);}printf("%d\n",ans);}return 0;
}

图片转自ac大神博客 Orz

[最小费用流 || KM算法]hdoj 3395:Special Fish相关推荐

  1. 最大流增广路(KM算法) HDOJ 1853 Cyclic Tour

    题目传送门 1 /* 2 KM: 相比HDOJ_1533,多了重边的处理,还有完美匹配的判定方法 3 */ 4 #include <cstdio> 5 #include <cmath ...

  2. [KM算法]hdoj 3722:Card Game

    大致题意:     要把n个字符串首尾相连成若干个环,如果把s1接到s2的后面可以得到一定的收获值,这个值等于s2的逆序 和s1的最长相同前缀的长度.求总收获值最大是多少. 大致思路:     看完题 ...

  3. [KM算法]hdoj 2853:Assignment

    大致题意: n个部队到m个地区抗震救灾(缅怀四川地震死难同胞).已知每只部队到每个地区的收益值,现在给出一种匹配方案.求出达到最大匹配时的收益值比当前匹配方案多多少,且需要有多少只部队的调动不需要改动 ...

  4. [KM算法]hdoj 3718:Similarity

    大致题意: 给你两个长度相同的字符串,问这两个串中的字母怎么样匹配才能使得总的复合度最大. 大致思路: 按照字母间的对应关系建二分图,求出最大全匹配后除以总长度. #include<cstdio ...

  5. [KM算法]hdoj 2426:Interesting Housing Problem

    大致题意: 有n个小孩要去m间屋子,每间屋子只能住一个人.每个小孩都会对一些屋子打分.已知每个小孩不能去那些他打负分和没打分的屋子,求安排住宿后所有人对自己屋子打分之和最大值是多少. 大致思路: KM ...

  6. km算法c语言,KM算法最好的讲解+POJ2195[KM算法+最小费用流]

    二.KM算法: 二分图最优匹配:对于二分图的每条边都有一个权(非负),要求一种完备匹配方案,使得所有匹配边的权和最大,记做最优完备匹配.(特殊的,当所有边的权为1时,就是最大完备匹配问题) 解二分图最 ...

  7. KM算法 入门——[kuangbin]KM匹配

    之前写过了关于普通二分匹配的相关题目了,就是寻找尽量多的边使得任意边连接的两点都没有与其他边相连,而km算法解决的则是在带权的二分图中寻找权值和最大的匹配,可以通过先给无连接的点连上权值为0或者负无穷 ...

  8. HDU 2255 奔小康赚大钱 带权二分图匹配 KM算法

    奔小康赚大钱 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Sub ...

  9. HDU(2255),KM算法,最大权匹配

    题目链接 奔小康赚大钱 Time Limit: 1000/1000MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Su ...

最新文章

  1. 使用Pixel Bender Toolkit制作特效——多像素采样(Part 4)
  2. android通知栏打开actvity,Android实现点击通知栏后,先启动应用再打开目标Activity...
  3. SpringMVC中的文件上传
  4. 连休8天!关于2020年国庆节、中秋节放假安排的通知!!!
  5. zeekooper集群搭建_How to do - ZooKeeper集群搭建(我见过最详细的完整教学)
  6. android assets文件夹资源的访问
  7. java——JMM内存模型
  8. JavaScript笔记集
  9. 手机怎么快速把jpg图片中的文字提取出来
  10. k2p 登录路由器shell失败_斐讯路由器无法进入路由器登录管理界面怎么办
  11. 报表工具ActiveReports开发实例——物联网智能供水云平台
  12. Graphics详解
  13. Up in the Air-16
  14. 游戏编辑器制作(3)
  15. ESP8266+blinker点灯(小爱+天猫+小度三合一)
  16. Python 读取xlsx表格
  17. 偏移出来的数据不准_cad偏移(cad偏移数据和输入的数据不准确)
  18. 批量识别图片大致不相同图片_电脑图片太多,其中不少是重复的,有无什么软件可以识别相同图片!...
  19. AIX7.1 安装配置 EMC Symmetrix 存储驱动软件
  20. fedora 安装与系统升级

热门文章

  1. 在应用商店中查找应用_Windows应用商店不是查找应用程序的唯一场所:这里有几种选择...
  2. Java坦克大战 (五) 之产生敌方坦克和爆炸效果
  3. 2020-用多通道卷积神经网络学习单类特征用于人脸表现攻击检测
  4. 求x的n次方(x^n) 库函数power
  5. Tensorflow2.0数据集下载
  6. 如何利用EasyDSS平台搭建 “网络慢直播”展示城市文化风光
  7. Flume 监控kafka主题写HDFS小结
  8. 强化学习笔记(7)基于模型的RL / Dyna算法/ MCTS
  9. 对融资融券和股指期货的看法
  10. MYSQL数据库课程-查询处理