博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
图论(KM算法,脑洞题):HNOI 2014 画框(frame)
阅读量:5040 次
发布时间:2019-06-12

本文共 2725 字,大约阅读时间需要 9 分钟。

  

  值得一写的脑洞题!

  最开始没有任何思路,看了题解后才会做。

  考虑将a的和与b的和表示为坐标,那么可能为答案的点一定是下凸包中的点,这样优化枚举就保证了效率。

  然而并不知道到底哪些点是凸包中的点,但我们知道边界的两点(a最小于b最小)一定在凸包上,如果已知两个凸包上的点,我们将它们连线,那么属于原图中的点若距离此直线最远,则一定是凸包上的点,于是可以二分,用向量的叉积求出那个点。

1 #include 
2 #include
3 #include
4 using namespace std; 5 const int maxn=120; 6 const int INF=1147483647; 7 int a[maxn][maxn],b[maxn][maxn]; 8 int w[maxn][maxn],sx[maxn],sy[maxn]; 9 int mat[maxn],sla[maxn];10 int lx[maxn],ly[maxn];11 int n,T;12 struct Dot{13 int x,y;14 Dot(int x_=0,int y_=0):x(x_),y(y_){}15 friend bool operator ==(Dot a,Dot b){16 return a.x==b.x&&a.y==b.y;17 }18 }lo,hi;19 bool DFS(int x){20 sx[x]=1;21 for(int y=1;y<=n;y++)22 if(!sy[y]){23 int t=lx[x]+ly[y]-w[x][y];24 if(t)sla[y]=min(sla[y],t);25 else{26 sy[y]=1;27 if(!mat[y]||DFS(mat[y]))28 {mat[y]=x;return true;}29 } 30 }31 return false; 32 }33 34 Dot KM(){35 memset(lx,0,sizeof(lx));36 memset(ly,0,sizeof(ly));37 memset(mat,0,sizeof(mat));38 for(int i=1;i<=n;i++)39 for(int j=1;j<=n;j++)40 lx[i]=max(lx[i],w[i][j]);41 42 for(int x=1;x<=n;x++){43 memset(sla,63,sizeof(sla));44 while(true){45 memset(sx,0,sizeof(sx));46 memset(sy,0,sizeof(sy));47 if(DFS(x))break;48 int Min=INF;49 for(int i=1;i<=n;i++)if(!sy[i])Min=min(Min,sla[i]);50 for(int i=1;i<=n;i++){51 if(sx[i])lx[i]-=Min;52 sy[i]?ly[i]+=Min:sla[i]-=Min;53 }54 }55 }56 Dot ret(0,0);57 for(int i=1;i<=n;i++){58 ret.x+=a[mat[i]][i];59 ret.y+=b[mat[i]][i];60 }61 return ret; 62 }63 64 int Solve(Dot l,Dot r){65 for(int i=1;i<=n;i++)66 for(int j=1;j<=n;j++)67 w[i][j]=a[i][j]*(r.y-l.y)-b[i][j]*(r.x-l.x);68 Dot mid=KM();69 if(mid==l||mid==r)return min(l.x*l.y,r.x*r.y);70 return min(Solve(l,mid),Solve(mid,r));71 }72 73 74 int main(){75 freopen("frame.in","r",stdin);76 freopen("frame.out","w",stdout);77 scanf("%d",&T);78 while(T--){79 scanf("%d",&n);80 for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)scanf("%d",&a[i][j]); 81 for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)scanf("%d",&b[i][j]); 82 for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)w[i][j]=-a[i][j];lo=KM();83 for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)w[i][j]=-b[i][j];hi=KM();84 printf("%d\n",Solve(lo,hi));85 }86 return 0;87 }

 

  

转载于:https://www.cnblogs.com/TenderRun/p/5699115.html

你可能感兴趣的文章
使用jquery中$.each()方法来循环一个数据列表
查看>>
BZOJ2002 [Hnoi2010]Bounce 弹飞绵羊 LCT
查看>>
JS中 Cookie、 LocalStorage 与 SessionStorage
查看>>
Android 热补丁动态修复框架小结
查看>>
View.VISIBLE、INVISIBLE、GONE的区别
查看>>
疲惫的周末
查看>>
关于hibernate查询映射时无法反序列化问题
查看>>
深度剖析HashMap的数据存储实现原理(看完必懂篇)
查看>>
77.Combinations
查看>>
java字符串的替换replace、replaceAll、replaceFirst的区别详解
查看>>
GUI学习之三——QObject学习总结
查看>>
Python学习1 基础数据类型
查看>>
开始Flask项目
查看>>
跟Google学习Android开发-起始篇-用碎片构建一个动态的用户界面(3)
查看>>
精密整流电路(AD630)
查看>>
实验四
查看>>
js判断手指滑动方向(移动端)
查看>>
POJ 2112 Optimal Milking (Dinic + Floyd + 二分)
查看>>
HDU 1003 Max Sum 求区间最大值 (尺取法)
查看>>
简单实现web单点登录
查看>>