bzoj 1027 floyd求有向图最小环

结合得好巧妙。。。。

化简后的问题是:

给你两个点集A,B,求B的一个子集BB,使得BB的凸包包含A的凸包,求BB的最小大小。

先特判答案为1,2的情况,答案为3的情况,我们先构造一个有向图:

对于B集合中的两个点u,v,如果 所有A集合的点都在u->v的左侧,那么就连一条u->v的边。

于是我们可以证明一个包含A的凸包和我们连出来的有向图中的环一一对应(不考虑点数小于等于2的情况)。

于是现在我们的问题就是求最小的一个环,用floyd搞,最后统计min(f[i][i])。

  1 /**************************************************************
  2     Problem: 1027
  3     User: idy002
  4     Language: C++
  5     Result: Accepted
  6     Time:1308 ms
  7     Memory:2008 kb
  8 ****************************************************************/
  9
 10 #include <cstdio>
 11 #include <cmath>
 12 #include <cstring>
 13 #include <algorithm>
 14 #define line(a,b) ((b)-(a))
 15 #define eps 1e-8
 16 #define oo 0x3f3f3f3f
 17 #define N 550
 18 using namespace std;
 19
 20 int sg( double x ) { return (x>-eps)-(x<eps); }
 21 struct Vector {
 22     double x, y;
 23     Vector(){}
 24     Vector( double x, double y ):x(x),y(y){}
 25     Vector operator-( const Vector &b ) const { return Vector(x-b.x,y-b.y); }
 26     double operator^( const Vector &b ) const { return x*b.y-y*b.x; }
 27     double operator&( const Vector &b ) const { return x*b.x+y*b.y; }
 28     double len() { return sqrt(x*x+y*y); }
 29     bool operator<( const Vector &b ) const {
 30         return sg(x-b.x)<0 || (sg(x-b.x)==0 && sg(y-b.y)<0);
 31     }
 32     bool operator==( const Vector &b ) const {
 33         return sg(x-b.x)==0 && sg(y-b.y)==0;
 34     }
 35 };
 36 typedef Vector Point;
 37
 38 int n, m;
 39 Point aa[N], bb[N];
 40 int dis[N][N];
 41
 42 bool onleft( const Point &a, const Point &b, const Point &c ) {
 43     return sg(line(a,b)^line(a,c))>=0;
 44 }
 45 bool onseg( const Point &a, const Point &b, const Point &c ) {
 46     return sg(line(a,b)^line(a,c))==0 && sg(line(c,a)&line(c,b))<0;
 47 }
 48 bool case1() {
 49     if( m==1 ) {
 50         for( int i=1; i<=n; i++ )
 51             if( aa[i]==bb[1] )
 52                 return true;
 53     }
 54     return false;
 55 }
 56 bool case2() {
 57     bool ok = true;
 58     for( int i=1; i<=m && ok; i++ )
 59         for( int j=i+1; j<=m && ok; j++ )
 60             for( int k=j+1; k<=m && ok; k++ )
 61                 if( sg((bb[i]-bb[j])^(bb[k]-bb[j])) )
 62                     ok =false;
 63     if( ok ) {
 64         int ii=1, jj=1;
 65         double ll = -1.0;
 66         for( int i=1; i<=m; i++ )
 67             for( int j=i+1; j<=m; j++ ) {
 68                 double l = (bb[i]-bb[j]).len();
 69                 if( l>ll ) {
 70                     ii = i;
 71                     jj = j;
 72                     ll = l;
 73                 }
 74             }
 75         for( int i=1; i<=n; i++ )
 76             for( int j=i+1; j<=n; j++ )
 77                 if( onseg(aa[i],aa[j],bb[ii]) && onseg(aa[i],aa[j],bb[jj]) )
 78                     return true;
 79     }
 80     return false;
 81 }
 82 int main() {
 83     scanf( "%d%d", &n, &m );
 84     for( int i=1; i<=n; i++ ) {
 85         double x, y, z;
 86         scanf( "%lf%lf%lf", &x, &y, &z );
 87         aa[i] = Point(x,y);
 88     }
 89     for( int i=1; i<=m; i++ ) {
 90         double x, y, z;
 91         scanf( "%lf%lf%lf", &x, &y, &z );
 92         bb[i] = Point(x,y);
 93     }
 94     sort( bb+1, bb+1+m );
 95     m = unique( bb+1, bb+1+m ) - bb - 1;
 96     sort( aa+1, aa+1+n );
 97     n = unique( aa+1, aa+1+n ) - aa - 1;
 98     if( case1() ) {
 99         printf( "1\n" );
100         return 0;
101     } else if( case2() ) {
102         printf( "2\n" );
103         return 0;
104     }
105     memset( dis, 0x3f, sizeof(dis) );
106     for( int u=1; u<=n; u++ )
107         for( int v=1; v<=n; v++ ) {
108             if( u==v ) continue;
109             bool ok = true;
110             for( int k=1; k<=m; k++ )
111                 if( !onleft(aa[u],aa[v],bb[k]) ) {
112                     ok = false;
113                     break;
114                 }
115             if( ok ) {
116                 dis[u][v] = 1;
117             }
118         }
119     for( int k=1; k<=n; k++ )
120         for( int i=1; i<=n; i++ )
121             for( int j=1; j<=n; j++ )
122                 dis[i][j] = min( dis[i][j], dis[i][k]+dis[k][j] );
123     int ans = oo;
124     for( int i=1; i<=n; i++ ) {
125         if( dis[i][i]==2 ) continue;
126         ans = min( ans, dis[i][i] );
127     }
128     printf( "%d\n", ans==oo ? -1 : ans );
129 }

时间: 2024-10-29 19:07:21

bzoj 1027 floyd求有向图最小环的相关文章

BZOJ 1027 合金(凸包-最小环)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1027 题意:三种合金的材料若干种.需求合金若干种.每种需求合金可以由材料合金混合得到.问最少需要多少种材料能够混合出所有需要的合金? 思路:对于两种材料合金ab,若能够得到需 求合金p,那么p必在线段ab上.这里由于三种合金的和为1,只要二维就够了,也就是是一个二维的问题.那么问题转化成,在平面上,找出最少的点包含所有 的需求合金对应的点(答案为1和2特判一下就行).两两枚举材料合金x

UVa 247 - Calling Circles(Floyd求有向图的传递闭包)

链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=183 题意: 如果两个人相互打电话(直接或间接),则说他们在同一个电话圈里.例如,a打给b,b打给c,c打给d,d打给a,则这4个人在同一个圈里:如果e打给f但f不打给e,则不能推出e和f在同一个电话圈里.输入n(n≤25)个人的m次电话,找出所有电话圈.人名只包含字母,不超过25个

FZU 2090 旅行社的烦恼 floyd 求无向图最小环

题目链接:旅行社的烦恼 题意是求无向图的最小环,如果有的话,输出个数,并且输出权值. 刚刚补了一发floyd 动态规划原理,用了滑动数组的思想.所以,这个题就是floyd思想的变形.在k从1到n的过程中更新到k时,mindis数组中保存的是只经过1~k-1序号的点时,任意两个之间的最短路权值,这时候,选择点k作为环的起点即终点,在[1, k)之间选择两个点i, j 得到一个环,环的权值即为mindis[i][j] + dis[i][k] + dis[j][k].这样遍历得到的是就是所有的环,且环

【BZOJ 1027】 (凸包+floyd求最小环)

[题意] 某公司加工一种由铁.铝.锡组成的合金.他们的工作很简单.首先进口一些铁铝锡合金原材料,不同种类的原材料中铁铝锡的比重不同.然后,将每种原材料取出一定量,经过融解.混合,得到新的合金.新的合金的铁铝锡比重为用户所需要的比重. 现在,用户给出了n种他们需要的合金,以及每种合金中铁铝锡的比重.公司希望能够订购最少种类的原材料,并且使用这些原材料可以加工出用户需要的所有种类的合金. [分析] 只要考虑前两个物质的比例,因为加起来等于1. 如果你看过zoj3154,就会知道这题的模型,用二元组表

[BZOJ 1027][JSOI2007]合金(计算几何+Floyd最小环)

Description 某公司加工一种由铁.铝.锡组成的合金.他们的工作很简单.首先进口一些铁铝锡合金原材料,不同种类的原材料中铁铝锡的比重不同.然后,将每种原材料取出一定量,经过融解.混合,得到新的合金.新的合金的铁铝锡比重为用户所需要的比重. 现在,用户给出了n种他们需要的合金,以及每种合金中铁铝锡的比重.公司希望能够订购最少种类的原材料,并且使用这些原材料可以加工出用户需要的所有种类的合金. Solution 今天考试T3的70分算法似乎是这道原题(然而我没做过QwQ) 思路值得学习一下(

多源最短路径Floyd、Floyd求最小环【模板】

Floyd算法:用来找出每对点之间的最短距离.图可以是无向图,也可以是有向图,边权可为正,也可以为负,唯一要求是不能有负环. 1.初始化:将Map[][]中的数据复制到Dist[][]中作为每对顶点之间的最短路径的初值,Pre[i][j] = i 表示 i 到 j 路径中 j 的前一节点. 2. k 从 1 到 N 循环 N 次,每次循环中,枚举图中不同的两点 i,j,如果Dist[i][j] > Dist[i][k] + Dist[k][j],则更新Dist[i][j] = Dist[i][k

HDU - 1599 find the mincost route(Floyd求最小环)

find the mincost route Time Limit: 2000MS Memory Limit: 32768KB 64bit IO Format: %I64d & %I64u Submit Status Description 杭州有N个景区,景区之间有一些双向的路来连接,现在8600想找一条旅游路线,这个路线从A点出发并且最后回到A点,假设经过的路线为V1,V2,....VK,V1,那么必须满足K>2,就是说至除了出发点以外至少要经过2个其他不同的景区,而且不能重复经过同一个

BZOJ 1027 JSOI2007 合金 计算几何+Floyd

题目大意:给定一些合金,选择最少的合金,使这些合金能够按比例合成要求的合金 首先这题的想法特别奇异 看这题干怎么会想到计算几何 并且计算几何又怎么会跟Floyd挂边 好强大 首先因为a+b+c=1 所以我们仅仅要得到a和b就可以 c=1-a-b 所以c能够不读入了 然后我们把每种原料抽象成一个点 可知两个点能合成的合金一定在两点连线的线段上 证明:设两个点为(x1,y1)和(x2,y2),新合成的合金为(ax1+bx2,ay2+by2) (a+b=1,a,b>0) 两点连线为(y-y1)/(x-

Floyd求最小环!(转载,非原创)

//Floyd 的 改进写法可以解决最小环问题,时间复杂度依然是 O(n^3),储存结构也是邻接矩阵 int mincircle = infinity; Dist = Graph; for(int k=0;k<nVertex;++k){ //新增部分: for(int i=0;i<k;++i) for(int j=0;j<i;++j) mincircle = min(mincircle,Dist[i][j]+Graph[j][k]+Graph[k][i]); //通常的 floyd 部分