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) 收藏 举报

浙公网安备 33010602011771号