http://poj.org/problem?id=3621
题意:
给定 一些 点的 欢乐值 ,和一些点的距离 ,求 是否存在一个环使得 ,欢乐值 /走的总距离, 最大 ;
题解:整数规划 问题。
首先的一个结论就是,不会存在环套环的问题,即最优的方案一定是一个单独的环,而不是大环套着小环的形式。这个的证明其实非常的简单,大家可以自己想一下 (提示,将大环上的收益和记为x1,花费为y1,小环上的为x2,y2。重叠部分的花费为S。表示出来分类讨论即可)。有了这个结论,我们就可以将花费和 收益都转移到边上来了,因为答案最终一定是一个环,所以我们将每一条边的收益规定为其终点的收益,这样一个环上所有的花费和收益都能够被正确的统计。
解决了蛋疼的问题之后,就是01分数规划的部分了,我们只需要计算出D数组后找找有没有正权环即可,用spfa(单源最短路径) 判断即可。
1 #include<cstdio>
2 #include<cstring>
3 #include<cmath>
4 #include<iostream>
5 #include<algorithm>
6 #include<set>
7 #include<map>
8 #include<queue>
9 #include<vector>
10 #include<string>
11 #define Min(a,b) a<b?a:b
12 #define Max(a,b) a>b?a:b
13 #define CL(a,num) memset(a,num,sizeof(a));
14 #define eps 1e-6
15 #define inf 10001000
16
17 #define ll __int64
18
19 #define read() freopen("data.txt","r",stdin) ;
20 const double pi = acos(-1.0);
21 const int maxn = 1024;
22
23 using namespace std;
24 struct node
25 {
26 int u;
27 int v;
28 int len ;
29 int next ;
30 }p[maxn*5] ;
31 int n , m ;
32 int cnt , head[maxn],num[maxn],a[maxn];
33 double dis[maxn];
34 int vis[maxn] ;
35 void add(int u,int v,int len )
36 {
37 p[cnt].v = v;
38 p[cnt].len = len;
39 p[cnt].next = head[u] ;
40 head[u] = cnt++ ;
41 }
42
43 queue<int>que;
44 bool spfa(double mid)
45 {
46 int i ;
47 while(!que.empty())que.pop() ;
48
49 for(i = 1 ; i <= n;i++)
50 {
51 dis[i] = -inf;
52
53
54 }
55
56 que.push(1) ;
57
58 dis[1] = 0;
59
60 CL(vis,0) ;
61
62 vis[1] = 1;
63
64 CL(num,0) ;
65
66
67
68 while(!que.empty())
69 {
70 int u = que.front() ;que.pop() ;
71 vis[u] = 0 ;
72 for(i = head[u];i !=-1 ;i = p[i].next)
73 {
74 int v = p[i].v ;
75 int len = p[i].len ;
76 double t = a[v] - mid * len ;
77 if(dis[u] + t > dis[v])
78 {
79 dis[v] = t + dis[u];
80 num[v] ++;
81 if(!vis[v])
82 {
83 que.push(v) ;
84 vis[v] = 1 ;
85
86
87 }
88 if(num[v] >= n) return true ;
89
90
91
92 }
93 }
94
95 }
96 return false ;
97 }
98 int main()
99 {
100 int i ;
101 int x,y;
102 int d;
103 //read() ;
104 while(scanf("%d%d",&n,&m)!=EOF)
105 {
106 cnt = 0 ;
107 CL(head,-1) ;
108 for(i = 1 ;i <= n;i++)
109 scanf("%d",&a[i]) ;
110 for(i = 0 ; i< m;i++)
111 {
112 scanf("%d%d%d",&x,&y,&d) ;
113 add(x,y,d);
114
115 }
116 double l = 0, r = 2500,mid;
117 double ans = -1;
118 while(r - l >= eps)
119 {
120 mid = (l + r)/2.0 ;
121 if(spfa(mid))
122 {
123 ans = mid;
124 l = mid ;
125 }
126 else r = mid ;
127 }
128
129 if(ans < 0)printf("0\n");//判断是否有环
130 else
131 printf("%.2lf\n",ans) ;
132
133
134 }
135 }
2 #include<cstring>
3 #include<cmath>
4 #include<iostream>
5 #include<algorithm>
6 #include<set>
7 #include<map>
8 #include<queue>
9 #include<vector>
10 #include<string>
11 #define Min(a,b) a<b?a:b
12 #define Max(a,b) a>b?a:b
13 #define CL(a,num) memset(a,num,sizeof(a));
14 #define eps 1e-6
15 #define inf 10001000
16
17 #define ll __int64
18
19 #define read() freopen("data.txt","r",stdin) ;
20 const double pi = acos(-1.0);
21 const int maxn = 1024;
22
23 using namespace std;
24 struct node
25 {
26 int u;
27 int v;
28 int len ;
29 int next ;
30 }p[maxn*5] ;
31 int n , m ;
32 int cnt , head[maxn],num[maxn],a[maxn];
33 double dis[maxn];
34 int vis[maxn] ;
35 void add(int u,int v,int len )
36 {
37 p[cnt].v = v;
38 p[cnt].len = len;
39 p[cnt].next = head[u] ;
40 head[u] = cnt++ ;
41 }
42
43 queue<int>que;
44 bool spfa(double mid)
45 {
46 int i ;
47 while(!que.empty())que.pop() ;
48
49 for(i = 1 ; i <= n;i++)
50 {
51 dis[i] = -inf;
52
53
54 }
55
56 que.push(1) ;
57
58 dis[1] = 0;
59
60 CL(vis,0) ;
61
62 vis[1] = 1;
63
64 CL(num,0) ;
65
66
67
68 while(!que.empty())
69 {
70 int u = que.front() ;que.pop() ;
71 vis[u] = 0 ;
72 for(i = head[u];i !=-1 ;i = p[i].next)
73 {
74 int v = p[i].v ;
75 int len = p[i].len ;
76 double t = a[v] - mid * len ;
77 if(dis[u] + t > dis[v])
78 {
79 dis[v] = t + dis[u];
80 num[v] ++;
81 if(!vis[v])
82 {
83 que.push(v) ;
84 vis[v] = 1 ;
85
86
87 }
88 if(num[v] >= n) return true ;
89
90
91
92 }
93 }
94
95 }
96 return false ;
97 }
98 int main()
99 {
100 int i ;
101 int x,y;
102 int d;
103 //read() ;
104 while(scanf("%d%d",&n,&m)!=EOF)
105 {
106 cnt = 0 ;
107 CL(head,-1) ;
108 for(i = 1 ;i <= n;i++)
109 scanf("%d",&a[i]) ;
110 for(i = 0 ; i< m;i++)
111 {
112 scanf("%d%d%d",&x,&y,&d) ;
113 add(x,y,d);
114
115 }
116 double l = 0, r = 2500,mid;
117 double ans = -1;
118 while(r - l >= eps)
119 {
120 mid = (l + r)/2.0 ;
121 if(spfa(mid))
122 {
123 ans = mid;
124 l = mid ;
125 }
126 else r = mid ;
127 }
128
129 if(ans < 0)printf("0\n");//判断是否有环
130 else
131 printf("%.2lf\n",ans) ;
132
133
134 }
135 }