HDU - 3666 THE MATRIX PROBLEM (差分约束~最短路~spfa优化)

THE MATRIX PROBLEM

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 8960    Accepted Submission(s): 2304


Problem Description
You have been given a matrix C N*M, each element E of C N*M is positive and no more than 1000, The problem is that if there exist N numbers a1, a2, … an and M numbers b1, b2, …, bm, which satisfies that each elements in row-i multiplied with ai and each elements in column-j divided by bj, after this operation every element in this matrix is between L and U, L indicates the lowerbound and U indicates the upperbound of these elements.
 

Input
There are several test cases. You should process to the end of file.
Each case includes two parts, in part 1, there are four integers in one line, N,M,L,U, indicating the matrix has N rows and M columns, L is the lowerbound and U is the upperbound (1<=N、M<=400,1<=L<=U<=10000). In part 2, there are N lines, each line includes M integers, and they are the elements of the matrix.

 

Output
If there is a solution print "YES", else print "NO".
 

Sample Input

  
3 3 1 62 3 48 2 65 2 9
 
Sample Output

  
YES
 

Source
 

Recommend

lcy   |   We have carefully selected several similar problems for you:  3665 3669 3667 3664 3663 

             对于一个n*m的矩阵W~想问是否有长的为n的序列a和长度为m的序列b ~~存在对任意L<=W[i][j]*a[i]/b[j]<=U;

             一眼望去就知道这是一道~关于构图加spfa判断负环的差分约束~但是刚开始根本不知道怎样构图(话说对于图论一直都是构图难~只要勾完图一个函数就出来~)~ 之后发现只要取对数~就会使式子变成::

             log(L)-log(W[i][j])<=log(a[i])-log(b[j])<=log(U)-log(W[i][j]);

             将每个log(a[i])和log(b[j])看成点~这里我是将j=j+n~让点不重复~然后你跑一个最短路就好了;

             结果就是我T了~~囧~感觉这道题非要用A_Star算法??

        感觉就很烦~~于是找了找资料~发现了两个关于spfa的优化~~SLF和LLL(我用了SLF这里,有兴趣可以看https://blog.csdn.net/oranges_c/article/details/64124235);

             我现在用的就是SLF~~SLF需要用到双端队列deque~这个存在于<queue>里面;大意就是每次插入~如果这个数t的距离大于队列的第一个数的距离~就把他插到队首~否则插到队尾~~!!这里一定要注意在队列为空时候的处理!!;

              这样优化后就能过了~其实我觉得SLF和A_*在意义上感觉差的不大~像是简化版本??

#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
#include <algorithm>
#include<cstring>
using namespace std;
#define inf 0x3f3f3f3f
struct fuck
{
	int to, ne;
	double len;
}ed[500000];
double d[50000];
int cnt = 0;
int head[50000];
void add(int from, int to, double len)
{
	ed[cnt].len = len;
	ed[cnt].to = to;
	ed[cnt].ne = head[from];
	head[from] = cnt++;
}
int a, b, mi, ma;
bool vis[50000];
int time[50000];
int spfa()
{
	deque<int>q;
	q.push_front(0);
	vis[0] = 1;
	d[0]=0;
	time[0]=1;
	while (!q.empty())
	{
		int t = q.front();//双端队列
		q.pop_front();//双端队列的插入弹出有他独特的函数~需要看下;
		vis[t] = 0;
		for (int s = head[t]; ~s; s = ed[s].ne)
		{
			if (d[ed[s].to]>d[t] + ed[s].len)
			{
				d[ed[s].to] = d[t] + ed[s].len;
				if (!vis[ed[s].to])
				{
					vis[ed[s].to] = 1;
					if (++time[ed[s].to]>=a + b)
					{
						return 0;
					}
					if(!q.empty())//注意队列为空时的处理
                    {
                        if(d[ed[s].to]<d[q.front()])
                        {
                            q.push_front(ed[s].to);
                        }
                        else
                        {
                            q.push_back(ed[s].to);
                        }
                    }
                    else
                    {
                        q.push_front(ed[s].to);
                    }
				}
			}
		}
	}
	return 1;
}
void init()
{
    memset(head,-1,sizeof(head));
	memset(vis, 0, sizeof(vis));
	memset(time, 0, sizeof(time));
	cnt = 0;
	memset(d, inf, sizeof(d));
}
int main()
{
	int m[500][500];
	while (scanf("%d%d%d%d", &a, &b, &mi, &ma)!=EOF)
	{
		init();
		for (int s = 1; s <= a; s++)
		{
			for (int e = 1; e <= b; e++)
			{
				scanf("%d", &m[s][e]);
				add(s, a + e, log(ma) - log(m[s][e]));//建图
				add(a + e, s, log(m[s][e]) - log(mi));
			}
		}
		for (int s = 1; s <= a + b; s++)//建立超级源点
		{
			add(0, s, 0);
		}
		if (spfa())
		{
			printf("YES\n");
		}
		else
		{
			printf("NO\n");
		}
	}
	return 0;
}




猜你喜欢

转载自blog.csdn.net/chenshibo17/article/details/80169058