码迷,mamicode.com
首页 > 编程语言 > 详细

图论(KM算法,脑洞题):HNOI 2014 画框(frame)

时间:2016-07-23 18:21:27      阅读:233      评论:0      收藏:0      [点我收藏+]

标签:

技术分享

技术分享

  

  值得一写的脑洞题!

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

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

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

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 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 }

 

  

图论(KM算法,脑洞题):HNOI 2014 画框(frame)

标签:

原文地址:http://www.cnblogs.com/TenderRun/p/5699115.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!