HDU 3666--差分约束系统

http://acm.hdu.edu.cn/showproblem.php?pid=3666

这题网上搜到的代码几乎都是错的,很多都是用队列写,然后判断负权回路都是大于sqrt(n)。这不科学。。。

这题的正解是DFS版SPFA,或者改用栈写。

题意:给你一个N*M的矩阵,求两列数a1,a2,a3...an 和 b1,b2.....bm使得对矩阵中的每个数进行下面的操作之后的值在[L,U]之间,操作为:a[i] * m[i][j] / b[j]。  N,M<=400

思路:差分约束。由题意可知,对于矩阵中的每个元素要满足的条件是:L <= a[i] * m[i][j] / b[j] <= U ,这样我们就可以得到下面的两个式子:L*b[j] <= a[i]  * m[i][j]  和 a[i] * m[i][j]  <= U*b[j] ,因为差分约束中dis[]前面没有系数,为了把系数取消掉,我们可以用对式子两遍取对数,就可以得到:log(b[j]) - log( a[i] ) <= log( m[i][j] / L) ,同理可以得到两个式子,最后用spfa判负环就可以得出答案了。

代码:

 

View Code
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<stack>
 4 #include<math.h>
 5 #include<algorithm>
 6 #include<cstring>
 7 using namespace std;
 8 #define maxn 1005
 9 struct Edge{
10     int v;
11     double w;
12 }edge[maxn*maxn];
13 int next[maxn*maxn],sum[maxn],node[maxn],n,m,vis[maxn],num;
14 double dist[maxn];
15 void add_edge(int u,int v,double w)
16 {
17     edge[num].v=v;
18     edge[num].w=w;
19     next[num]=node[u];
20     node[u]=num++;
21 }
22 bool SPFA()
23 {
24     stack<int> q;
25     q.push(1);
26     dist[1]=0;
27     memset(vis,0,sizeof(vis));
28     memset(sum,0,sizeof(sum));
29     sum[1]++;
30     vis[1]=1;
31     while(!q.empty())
32     {
33         int x=q.top();
34         if(sum[x]>n+m)
35             return 0;
36         vis[x]=0;
37         q.pop();
38         for(int r=node[x];r!=-1;r=next[r])
39         {
40             int v=edge[r].v;
41             if(dist[v]<dist[x]+edge[r].w)
42             {
43                 dist[v]=dist[x]+edge[r].w;
44                 if(!vis[v])
45                 {
46                     vis[v]=1;
47                     sum[v]++;
48                     q.push(v);
49                 }
50             }
51         }
52     }
53     return 1;
54 }
55 int main()
56 {
57     int L,U,a,i,j;
58     while(~scanf("%d %d %d %d",&n,&m,&L,&U))
59     {
60         memset(node,-1,sizeof(node));
61         num=0;
62         for(i=1;i<=n;i++)
63             for(j=1;j<=m;j++)
64             {
65                 scanf("%d",&a);
66                 add_edge(j+n,i,log((double)L/(double)a));
67                 add_edge(i,j+n,log((double)a/(double)U));
68             }
69         for(i=1;i<=n+m;i++)
70             dist[i]=-999999999;
71         if(SPFA())
72             puts("YES");
73         else
74             puts("NO");
75     }
76     return 0;
77 }

 

还是不太熟练邻接表的操作。。edge的下标应该有maxn*maxn,而next的下标要与其一样大,因为这个查了一晚上,弱爆了。。

附上某位大神的DFS版SPFA写法:

View Code
 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<algorithm>
 4 #include<math.h>
 5 #include<queue>
 6 using namespace std;
 7 #define maxn 1000
 8 int head[maxn];
 9 struct bian
10 {
11     int v,next;
12     double w;
13 }edge[maxn*maxn];
14 int num;
15 int N,M,L,U;
16 queue<int>q;
17 int have[maxn];
18 bool vis[maxn];
19 double dis[1000];
20 void add(int u,int v,double w)
21 {
22     edge[num].v=v;
23     edge[num].next=head[u];
24     edge[num].w=w;
25     head[u]=num++;
26 }
27 int spfa(int u)
28 {
29     vis[u]=1;
30     for(int h=head[u];h!=-1;h=edge[h].next)
31     {
32         int v=edge[h].v;
33         if(dis[v]<dis[u]+edge[h].w)
34         {
35             dis[v]=dis[u]+edge[h].w;
36             if(vis[v])
37                 return v;
38             int ret=spfa(v);
39             if(ret!=-1)
40                 return ret;
41         }
42     }
43     vis[u]=0;
44     return -1;
45 }
46 int pan()
47 {
48     memset(vis,0,sizeof(vis));
49     memset(dis,0,sizeof(dis));
50     for(int i=1;i<=M+N;i++)
51     {
52         int ret=spfa(i);
53         if(ret!=-1)
54             return ret;
55     }
56     return -1;
57 }
58 int main()
59 {
60     while(scanf("%d%d%d%d",&N,&M,&L,&U)!=EOF)
61     {
62         num=0;
63         memset(head,-1,sizeof(head));
64         for(int i=1;i<=N;i++)
65         {
66             for(int j=1;j<=M;j++)
67             {
68                 int a;
69                 scanf("%d",&a);
70                 add(j+N,i,log((double)L/(double)a));
71                 add(i,j+N,log((double)a/(double)U));
72             }
73         }
74         if(pan()==-1)
75             printf("YES\n");
76         else
77             printf("NO\n");
78     }
79 }

 

 

posted on 2013-02-04 20:03  acoderworld  阅读(112)  评论(0)    收藏  举报

导航