【HDU】4975 A simple Gaussian elimination problem. 网络流——行列建边

2024-09-05 15:08

本文主要是介绍【HDU】4975 A simple Gaussian elimination problem. 网络流——行列建边,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

传送门:【HDU】4975 A simple Gaussian elimination problem.


题目分析:这题和某一场的多校的题目出奇的像啊!重要的是我一开始还以为不可能会出一样的题。。结果迟迟没写啊。。。后来觉得实在想不出什么对策了,虽然觉得给的是0~9很特殊,但是利用不起来,果断还是敲了网络流了。。首先建图很简单,源点向行建边,容量为行和,列向汇点建边,容量为列和,然后所有的行向所有的列建边,跑一边最大流,如果流量和元素总和不相等则无解。

现在关键就是求单解还是多解了。姿势不对可是就会TLE的哦~~

然后我很光荣的TLE了 T U T。。。

首先用残余网络判环的方法可以过(难以置信。。。),然后我用O(n^3)寻找可以使得多解存在的四个点的矩阵(矩阵的四个点如果满足其中一条对角线上的两点可以变小,另一条上的两个可以变大,则说明存在多解),不出意外的TLE了!不过我郁闷了很久突然想到如果一行的元素都为0或者都为9时这一行一定是无用的(不可能同时存在两点一点可以增大,另一点可以减小),将其判掉,然后再交了一发,期待的看着板板,然后终于给我返回了一个期待已久的———TLE!

郁闷至极啊!!!

然后想了想就弃疗了再特判掉列吧,怀着不可能AC的心再交了一发。。。然后在我不可思议的眼中,它竟然AC了?!

果然流氓剪枝很强啊。。。

虽然还是跑不过前面大神的代码,但是已经满足啦~~


代码如下:


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <math.h>
using namespace std ;#define REP( i , a , b ) for ( int i = a ; i < b ; ++ i )
#define FOR( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define REV( i , a , b ) for ( int i = a ; i >= b ; -- i )
#define CLR( a , x ) memset ( a , x , sizeof a )
#define CPY( a , x ) memcpy ( a , x , sizeof a )const int MAXN = 1005 ;
const int MAXE = 2000000 ;
const int INF = 0x3f3f3f3f ;struct Edge {int v , c , n ;Edge () {}Edge ( int v , int c , int n ) : v ( v ) , c ( c ) , n ( n ) {}
} ;struct ISAP {Edge E[MAXE] ;int H[MAXN] , cntE ;int d[MAXN] , cur[MAXN] , num[MAXN] , pre[MAXN] ;int Q[MAXN] , head , tail ;int s , t , nv ;int flow ;void init () {cntE = 0 ;CLR ( H , -1 ) ;}void addedge ( int u , int v , int c ) {E[cntE] = Edge ( v , c , H[u] ) ;H[u] = cntE ++ ;E[cntE] = Edge ( u , 0 , H[v] ) ;H[v] = cntE ++ ;}void rev_bfs () {CLR ( d , -1 ) ;CLR ( num , 0 ) ;head = tail = 0 ;d[t] = 0 ;num[d[t]] = 1 ;Q[tail ++] = t ;while ( head != tail ) {int u = Q[head ++] ;for ( int i = H[u] ; ~i ; i = E[i].n ) {int v = E[i].v ;if ( ~d[v] ) continue ;d[v] = d[u] + 1 ;Q[tail ++] = v ;num[d[v]] ++ ;}}}int isap () {rev_bfs () ;CPY ( cur , H ) ;flow = 0 ;int u = pre[s] = s , i , pos , minv ;while ( d[s] < nv ) {if ( u == t ) {int f = INF ;for ( i = s ; i != t ; i = E[cur[i]].v )if ( f > E[cur[i]].c ) {f = E[cur[i]].c ;pos = i ;}for ( i = s ; i != t ; i = E[cur[i]].v ) {E[cur[i]].c -= f ;E[cur[i] ^ 1].c += f ;}flow += f ;u = pos ;}for ( i = cur[u] ; ~i ; i = E[i].n )if ( E[i].c && d[u] == d[E[i].v] + 1 ) break ;if ( ~i ) {cur[u] = i ;pre[E[i].v] = u ;u = E[i].v ;} else {if ( 0 == -- num[d[u]] ) break ;for ( minv = nv , i = H[u] ; ~i ; i = E[i].n ) {if ( E[i].c && minv > d[E[i].v] ) {minv = d[E[i].v] ;cur[u] = i ;}}d[u] = minv + 1 ;num[d[u]] ++ ;u = pre[u] ;}}return flow ;}
} S ;int n , m ;
int G[MAXN][MAXN] ;
int row[505] , col[505] ;
bool vis[505][505] ;bool unique () {CLR ( vis , 0 ) ;FOR ( i , 1 , n ) {if ( row[i] == 0 || row[i] == 9 * m ) continue ;FOR ( j , 1 , m ) {if ( col[j] == 0 || col[j] == 9 * n ) continue ;FOR ( k , j + 1 , m ) {int tmp1 = 0 , tmp2 = 0 ;if ( G[i][j] && G[i][k] != 9 ) {if ( vis[j][k] ) return 0 ;tmp1 = 1 ;}if ( G[i][k] && G[i][j] != 9 ) {if ( vis[k][j] ) return 0 ;tmp2 = 1 ;}if ( tmp1 ) vis[k][j] = 1 ;if ( tmp2 ) vis[j][k] = 1 ;}}}//FOR ( i , 1 , m ) FOR ( j , 1 , m ) printf ( "%d\n" , vis[i][j] ) ;return 1 ;
}void solve () {int sum1 = 0 , sum2 = 0 ;S.init () ;scanf ( "%d%d" , &n , &m ) ;S.s = 0 ;S.t = n + m + 1 ;S.nv = S.t + 1 ;FOR ( i , 1 , n ) {scanf ( "%d" , &row[i] ) ;S.addedge ( S.s , i , row[i] ) ;sum1 += row[i] ;}FOR ( i , 1 , m ) {scanf ( "%d" , &col[i] ) ;S.addedge ( i + n , S.t , col[i] ) ;sum2 += col[i] ;}if ( sum1 != sum2 ) {printf ( "So naive!\n" ) ;return ;}FOR ( i , 1 , n ) FOR ( j , 1 , m ) S.addedge ( i , j + n , 9 ) ;if ( sum1 != S.isap () ) {printf ( "So naive!\n" ) ;return ;}FOR ( u , 1 , n ) {for ( int i = S.H[u] ; ~i ; i = S.E[i].n ) {int v = S.E[i].v ;if ( v == 0 ) continue ;G[u][v - n] = 9 - S.E[i].c ;}}//FOR ( i , 1 , n ) FOR ( j , 1 , m ) printf ( "%d%c" , G[i][j] , j < m ? ' ' : '\n' ) ;if ( unique () ) printf ( "So simple!\n" ) ;else printf ( "So young!\n" ) ;
}int main () {int T , cas = 0 ;scanf ( "%d" , &T ) ;while ( T -- ) {printf ( "Case #%d: " , ++ cas ) ;solve () ;}return 0 ;
}


这篇关于【HDU】4975 A simple Gaussian elimination problem. 网络流——行列建边的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1139307

相关文章

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

hdu 2093 考试排名(sscanf)

模拟题。 直接从教程里拉解析。 因为表格里的数据格式不统一。有时候有"()",有时候又没有。而它也不会给我们提示。 这种情况下,就只能它它们统一看作字符串来处理了。现在就请出我们的主角sscanf()! sscanf 语法: #include int sscanf( const char *buffer, const char *format, ... ); 函数sscanf()和

hdu 2602 and poj 3624(01背包)

01背包的模板题。 hdu2602代码: #include<stdio.h>#include<string.h>const int MaxN = 1001;int max(int a, int b){return a > b ? a : b;}int w[MaxN];int v[MaxN];int dp[MaxN];int main(){int T;int N, V;s

uva 10014 Simple calculations(数学推导)

直接按照题意来推导最后的结果就行了。 开始的时候只做到了第一个推导,第二次没有继续下去。 代码: #include<stdio.h>int main(){int T, n, i;double a, aa, sum, temp, ans;scanf("%d", &T);while(T--){scanf("%d", &n);scanf("%lf", &first);scanf

hdu 1754 I Hate It(线段树,单点更新,区间最值)

题意是求一个线段中的最大数。 线段树的模板题,试用了一下交大的模板。效率有点略低。 代码: #include <stdio.h>#include <string.h>#define TREE_SIZE (1 << (20))//const int TREE_SIZE = 200000 + 10;int max(int a, int b){return a > b ? a :

hdu 1166 敌兵布阵(树状数组 or 线段树)

题意是求一个线段的和,在线段上可以进行加减的修改。 树状数组的模板题。 代码: #include <stdio.h>#include <string.h>const int maxn = 50000 + 1;int c[maxn];int n;int lowbit(int x){return x & -x;}void add(int x, int num){while

uva 10025 The ? 1 ? 2 ? ... ? n = k problem(数学)

题意是    ?  1  ?  2  ?  ...  ?  n = k 式子中给k,? 处可以填 + 也可以填 - ,问最小满足条件的n。 e.g k = 12  - 1 + 2 + 3 + 4 + 5 + 6 - 7 = 12 with n = 7。 先给证明,令 S(n) = 1 + 2 + 3 + 4 + 5 + .... + n 暴搜n,搜出当 S(n) >=